linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/24] drivers, fs: y2038 updates
@ 2019-12-13 20:49 Arnd Bergmann
  2019-12-13 20:49 ` [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64 Arnd Bergmann
                   ` (23 more replies)
  0 siblings, 24 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:49 UTC (permalink / raw)
  To: y2038, linux-kernel
  Cc: Arnd Bergmann, jdike, richard, jcmvbkbc, stefanr, l.stach,
	linux+etnaviv, christian.gmeiner, airlied, daniel, robdclark,
	sean, valdis.kletnieks, gregkh, ccaulfie, teigland, hirofumi,
	jack, davem, fw, viro, rfontana, tglx, linux-um, linux1394-devel,
	etnaviv, dri-devel, linux-arm-msm, freedreno, devel,
	cluster-devel, linux-fsdevel, netdev, trond.myklebust,
	anna.schumaker, linux-nfs, linux-xfs, darrick.wong, sparclinux

These are updates to devidce drivers and file systems that for some
reason or another were not included in the kernel in the previous
y2038 series.

I've gone through all users of time_t again to make sure the
kernel is in a long-term maintainable state.

Posting these as a series for better organization, but each change
here is applicable standalone.

Please merge, review, ack/nack etc as you see fit. I will
add these to my y2038 branch [1] for linux-next, but can keep
rebasing for feedback and to remove any patches that get
picked up by a maintainer.

Changes since v1 [2]:

- Add Acks I received
- Rebase to v5.5-rc1, droping patches that got merged already
- Add NFS, XFS and the final three patches from another series
- Rewrite etnaviv patches

      Arnd

[1] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=y2038
[2] https://lore.kernel.org/lkml/20191108213257.3097633-1-arnd@arndb.de/

Arnd Bergmann (24):
  Input: input_event: fix struct padding on sparc64
  fat: use prandom_u32() for i_generation
  dlm: use SO_SNDTIMEO_NEW instead of SO_SNDTIMEO_OLD
  xtensa: ISS: avoid struct timeval
  um: ubd: use 64-bit time_t where possible
  acct: stop using get_seconds()
  tsacct: add 64-bit btime field
  packet: clarify timestamp overflow
  quota: avoid time_t in v1_disk_dqblk definition
  hostfs: pass 64-bit timestamps to/from user space
  hfs/hfsplus: use 64-bit inode timestamps
  drm/msm: avoid using 'timespec'
  drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  drm/etnaviv: avoid deprecated timespec
  sunrpc: convert to time64_t for expiry
  nfs: use time64_t internally
  nfs: fix timstamp debug prints
  nfs: fscache: use timespec64 in inode auxdata
  xfs: rename compat_time_t to old_time32_t
  xfs: disallow broken ioctls without compat-32-bit-time
  xfs: quota: move to time64_t interfaces
  y2038: remove obsolete jiffies conversion functions
  y2038: rename itimerval to __kernel_old_itimerval
  y2038: sparc: remove use of struct timex

 arch/sparc/kernel/sys_sparc_64.c              | 29 +++++-----
 arch/um/drivers/cow.h                         |  2 +-
 arch/um/drivers/cow_user.c                    |  7 ++-
 arch/um/drivers/ubd_kern.c                    | 10 ++--
 arch/um/include/shared/os.h                   |  2 +-
 arch/um/os-Linux/file.c                       |  2 +-
 .../platforms/iss/include/platform/simcall.h  |  4 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.c         | 20 ++++---
 drivers/gpu/drm/etnaviv/etnaviv_drv.h         | 11 ++--
 drivers/gpu/drm/etnaviv/etnaviv_gem.c         |  4 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem.h         |  2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c         |  5 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h         |  5 +-
 drivers/gpu/drm/msm/msm_drv.h                 |  3 +-
 drivers/input/evdev.c                         | 14 ++---
 drivers/input/misc/uinput.c                   | 14 +++--
 fs/dlm/lowcomms.c                             |  6 +-
 fs/fat/inode.c                                |  3 +-
 fs/hfs/hfs_fs.h                               | 28 +++++++--
 fs/hfs/inode.c                                |  4 +-
 fs/hfsplus/hfsplus_fs.h                       | 28 +++++++--
 fs/hfsplus/inode.c                            | 12 ++--
 fs/hostfs/hostfs.h                            | 22 ++++---
 fs/hostfs/hostfs_kern.c                       | 15 +++--
 fs/nfs/fscache-index.c                        |  6 +-
 fs/nfs/fscache.c                              | 18 ++++--
 fs/nfs/fscache.h                              |  8 ++-
 fs/nfs/nfs4xdr.c                              | 10 ++--
 fs/quota/quotaio_v1.h                         |  6 +-
 fs/xfs/xfs_dquot.c                            |  6 +-
 fs/xfs/xfs_ioctl.c                            | 26 +++++++++
 fs/xfs/xfs_ioctl32.c                          |  2 +-
 fs/xfs/xfs_ioctl32.h                          |  2 +-
 fs/xfs/xfs_qm.h                               |  6 +-
 fs/xfs/xfs_quotaops.c                         |  6 +-
 fs/xfs/xfs_trans_dquot.c                      |  8 ++-
 include/linux/jiffies.h                       | 20 -------
 include/linux/sunrpc/cache.h                  | 42 ++++++++------
 include/linux/sunrpc/gss_api.h                |  4 +-
 include/linux/sunrpc/gss_krb5.h               |  2 +-
 include/linux/syscalls.h                      |  9 ++-
 include/uapi/linux/acct.h                     |  2 +
 include/uapi/linux/input.h                    |  1 +
 include/uapi/linux/taskstats.h                |  6 +-
 include/uapi/linux/time_types.h               |  5 ++
 include/uapi/linux/timex.h                    |  2 +
 kernel/acct.c                                 |  4 +-
 kernel/time/itimer.c                          | 18 +++---
 kernel/time/time.c                            | 58 ++-----------------
 kernel/tsacct.c                               |  9 ++-
 net/packet/af_packet.c                        | 27 +++++----
 net/sunrpc/auth_gss/gss_krb5_mech.c           | 12 +++-
 net/sunrpc/auth_gss/gss_krb5_seal.c           |  8 +--
 net/sunrpc/auth_gss/gss_krb5_unseal.c         |  6 +-
 net/sunrpc/auth_gss/gss_krb5_wrap.c           | 16 ++---
 net/sunrpc/auth_gss/gss_mech_switch.c         |  2 +-
 net/sunrpc/auth_gss/svcauth_gss.c             |  6 +-
 net/sunrpc/cache.c                            | 16 ++---
 net/sunrpc/svcauth_unix.c                     | 10 ++--
 59 files changed, 351 insertions(+), 290 deletions(-)

-- 
2.20.0

Cc: jdike@addtoit.com
Cc: richard@nod.at
Cc: jcmvbkbc@gmail.com
Cc: stefanr@s5r6.in-berlin.de
Cc: l.stach@pengutronix.de
Cc: linux+etnaviv@armlinux.org.uk
Cc: christian.gmeiner@gmail.com
Cc: airlied@linux.ie
Cc: daniel@ffwll.ch
Cc: robdclark@gmail.com
Cc: sean@poorly.run
Cc: valdis.kletnieks@vt.edu
Cc: gregkh@linuxfoundation.org
Cc: ccaulfie@redhat.com
Cc: teigland@redhat.com
Cc: hirofumi@mail.parknet.co.jp
Cc: jack@suse.com
Cc: davem@davemloft.net
Cc: fw@strlen.de
Cc: viro@zeniv.linux.org.uk
Cc: rfontana@redhat.com
Cc: tglx@linutronix.de
Cc: linux-um@lists.infradead.org
Cc: linux1394-devel@lists.sourceforge.net
Cc: etnaviv@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Cc: devel@driverdev.osuosl.org
Cc: cluster-devel@redhat.com
Cc: linux-fsdevel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: trond.myklebust@hammerspace.com
Cc: anna.schumaker@netapp.com
Cc: linux-nfs@vger.kernel.org
Cc: linux-xfs@vger.kernel.org
Cc: darrick.wong@oracle.com
Cc: sparclinux@vger.kernel.org

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
@ 2019-12-13 20:49 ` Arnd Bergmann
  2019-12-13 22:08   ` Dmitry Torokhov
  2019-12-13 20:49 ` [PATCH v2 02/24] fat: use prandom_u32() for i_generation Arnd Bergmann
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:49 UTC (permalink / raw)
  To: y2038, linux-kernel, Dmitry Torokhov, Deepa Dinamani
  Cc: Arnd Bergmann, sparclinux, David S. Miller, stable,
	Bjorn Helgaas, Lubomir Rintel, Thomas Gleixner, linux-input

Going through all uses of timeval, I noticed that we screwed up
input_event in the previous attempts to fix it:

The time fields now match between kernel and user space, but
all following fields are in the wrong place.

Add the required padding that is implied by the glibc timeval
definition to fix the layout, and use a struct initializer
to avoid leaking kernel stack data.

Cc: sparclinux@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>
Fixes: 141e5dcaa735 ("Input: input_event - fix the CONFIG_SPARC64 mixup")
Fixes: 2e746942ebac ("Input: input_event - provide override for sparc64")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/input/evdev.c       | 14 +++++++-------
 drivers/input/misc/uinput.c | 14 +++++++++-----
 include/uapi/linux/input.h  |  1 +
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index d7dd6fcf2db0..f918fca9ada3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -224,13 +224,13 @@ static void __pass_event(struct evdev_client *client,
 		 */
 		client->tail = (client->head - 2) & (client->bufsize - 1);
 
-		client->buffer[client->tail].input_event_sec =
-						event->input_event_sec;
-		client->buffer[client->tail].input_event_usec =
-						event->input_event_usec;
-		client->buffer[client->tail].type = EV_SYN;
-		client->buffer[client->tail].code = SYN_DROPPED;
-		client->buffer[client->tail].value = 0;
+		client->buffer[client->tail] = (struct input_event) {
+			.input_event_sec = event->input_event_sec,
+			.input_event_usec = event->input_event_usec,
+			.type = EV_SYN,
+			.code = SYN_DROPPED,
+			.value = 0,
+		};
 
 		client->packet_head = client->tail;
 	}
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index fd253781be71..2dabbe47d43e 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -74,12 +74,16 @@ static int uinput_dev_event(struct input_dev *dev,
 	struct uinput_device	*udev = input_get_drvdata(dev);
 	struct timespec64	ts;
 
-	udev->buff[udev->head].type = type;
-	udev->buff[udev->head].code = code;
-	udev->buff[udev->head].value = value;
 	ktime_get_ts64(&ts);
-	udev->buff[udev->head].input_event_sec = ts.tv_sec;
-	udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+	udev->buff[udev->head] = (struct input_event) {
+		.input_event_sec = ts.tv_sec,
+		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,
+		.type = type,
+		.code = code,
+		.value = value,
+	};
+
 	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
 
 	wake_up_interruptible(&udev->waitq);
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index f056b2a00d5c..9a61c28ed3ae 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -34,6 +34,7 @@ struct input_event {
 	__kernel_ulong_t __sec;
 #if defined(__sparc__) && defined(__arch64__)
 	unsigned int __usec;
+	unsigned int __pad;
 #else
 	__kernel_ulong_t __usec;
 #endif
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 02/24] fat: use prandom_u32() for i_generation
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
  2019-12-13 20:49 ` [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64 Arnd Bergmann
@ 2019-12-13 20:49 ` Arnd Bergmann
  2019-12-13 20:49 ` [PATCH v2 03/24] dlm: use SO_SNDTIMEO_NEW instead of SO_SNDTIMEO_OLD Arnd Bergmann
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:49 UTC (permalink / raw)
  To: y2038, linux-kernel, OGAWA Hirofumi
  Cc: Arnd Bergmann, Carmeli Tamir, Andrew Morton, Sergey Senozhatsky,
	Al Viro, Thomas Gleixner, Deepa Dinamani

Similar to commit 46c9a946d766 ("shmem: use monotonic time for i_generation")
we should not use the deprecated get_seconds() interface for i_generation.

prandom_u32() is the replacement used in other file systems.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/fat/inode.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 5f04c5c810fb..594b05ae16c9 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -21,6 +21,7 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <asm/unaligned.h>
+#include <linux/random.h>
 #include <linux/iversion.h>
 #include "fat.h"
 
@@ -521,7 +522,7 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
 	inode_inc_iversion(inode);
-	inode->i_generation = get_seconds();
+	inode->i_generation = prandom_u32();
 
 	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
 		inode->i_generation &= ~1;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 03/24] dlm: use SO_SNDTIMEO_NEW instead of SO_SNDTIMEO_OLD
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
  2019-12-13 20:49 ` [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64 Arnd Bergmann
  2019-12-13 20:49 ` [PATCH v2 02/24] fat: use prandom_u32() for i_generation Arnd Bergmann
@ 2019-12-13 20:49 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 04/24] xtensa: ISS: avoid struct timeval Arnd Bergmann
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:49 UTC (permalink / raw)
  To: y2038, linux-kernel, Christine Caulfield, David Teigland
  Cc: Arnd Bergmann, Deepa Dinamani, Richard Fontana, Thomas Gleixner,
	cluster-devel

Eliminate one more use of 'struct timeval' from the kernel so
we can eventually remove the definition as well.

The kernel supports the new format with a 64-bit time_t version
of timeval here, so use that instead of the old timeval.

Acked-by: Deepa Dinamani <deepa.kernel@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/dlm/lowcomms.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 3951d39b9b75..cdfaf4f0e11a 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1035,7 +1035,7 @@ static void sctp_connect_to_sock(struct connection *con)
 	int result;
 	int addr_len;
 	struct socket *sock;
-	struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
+	struct __kernel_sock_timeval tv = { .tv_sec = 5, .tv_usec = 0 };
 
 	if (con->nodeid == 0) {
 		log_print("attempt to connect sock 0 foiled");
@@ -1087,12 +1087,12 @@ static void sctp_connect_to_sock(struct connection *con)
 	 * since O_NONBLOCK argument in connect() function does not work here,
 	 * then, we should restore the default value of this attribute.
 	 */
-	kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_OLD, (char *)&tv,
+	kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_NEW, (char *)&tv,
 			  sizeof(tv));
 	result = sock->ops->connect(sock, (struct sockaddr *)&daddr, addr_len,
 				   0);
 	memset(&tv, 0, sizeof(tv));
-	kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_OLD, (char *)&tv,
+	kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO_NEW, (char *)&tv,
 			  sizeof(tv));
 
 	if (result == -EINPROGRESS)
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 04/24] xtensa: ISS: avoid struct timeval
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (2 preceding siblings ...)
  2019-12-13 20:49 ` [PATCH v2 03/24] dlm: use SO_SNDTIMEO_NEW instead of SO_SNDTIMEO_OLD Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 05/24] um: ubd: use 64-bit time_t where possible Arnd Bergmann
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel, Chris Zankel, Max Filippov; +Cc: Arnd Bergmann

'struct timeval' will get removed from the kernel, change the one
user in arch/xtensa to avoid referencing it, by using a fixed-length
array instead.

Acked-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/xtensa/platforms/iss/include/platform/simcall.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/xtensa/platforms/iss/include/platform/simcall.h b/arch/xtensa/platforms/iss/include/platform/simcall.h
index 2ba45858e50a..4e2a48380dbf 100644
--- a/arch/xtensa/platforms/iss/include/platform/simcall.h
+++ b/arch/xtensa/platforms/iss/include/platform/simcall.h
@@ -113,9 +113,9 @@ static inline int simc_write(int fd, const void *buf, size_t count)
 
 static inline int simc_poll(int fd)
 {
-	struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+	long timeval[2] = { 0, 0 };
 
-	return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv);
+	return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&timeval);
 }
 
 static inline int simc_lseek(int fd, uint32_t off, int whence)
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 05/24] um: ubd: use 64-bit time_t where possible
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (3 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 04/24] xtensa: ISS: avoid struct timeval Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 06/24] acct: stop using get_seconds() Arnd Bergmann
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel, Jeff Dike, Richard Weinberger, Anton Ivanov
  Cc: Arnd Bergmann, Alex Dewar, Jens Axboe, linux-um

The ubd code suffers from a possible y2038 overflow on 32-bit
architectures, both for the cow header and the os_file_modtime()
function.

Replace time_t with time64_t to extend the ubd_kern side as much
as possible.

Whether this makes a difference for the user side depends on
the host libc implementation that may use either 32-bit or 64-bit
time_t.

For the cow file format, the header contains an unsigned 32-bit
timestamp, which is good until y2106, passing this through a
'long long' gives us a consistent interpretation between 32-bit
and 64-bit um kernels.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/um/drivers/cow.h       |  2 +-
 arch/um/drivers/cow_user.c  |  7 ++++---
 arch/um/drivers/ubd_kern.c  | 10 +++++-----
 arch/um/include/shared/os.h |  2 +-
 arch/um/os-Linux/file.c     |  2 +-
 5 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
index 760c507dd5b6..103adac691ed 100644
--- a/arch/um/drivers/cow.h
+++ b/arch/um/drivers/cow.h
@@ -11,7 +11,7 @@ extern int init_cow_file(int fd, char *cow_file, char *backing_file,
 extern int file_reader(__u64 offset, char *buf, int len, void *arg);
 extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
 			   void *arg, __u32 *version_out,
-			   char **backing_file_out, time_t *mtime_out,
+			   char **backing_file_out, long long *mtime_out,
 			   unsigned long long *size_out, int *sectorsize_out,
 			   __u32 *align_out, int *bitmap_offset_out);
 
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
index 74b0c2686c95..29b46581ddd1 100644
--- a/arch/um/drivers/cow_user.c
+++ b/arch/um/drivers/cow_user.c
@@ -17,6 +17,7 @@
 
 #define PATH_LEN_V1 256
 
+/* unsigned time_t works until year 2106 */
 typedef __u32 time32_t;
 
 struct cow_header_v1 {
@@ -197,7 +198,7 @@ int write_cow_header(char *cow_file, int fd, char *backing_file,
 		     int sectorsize, int alignment, unsigned long long *size)
 {
 	struct cow_header_v3 *header;
-	unsigned long modtime;
+	long long modtime;
 	int err;
 
 	err = cow_seek_file(fd, 0);
@@ -276,7 +277,7 @@ int file_reader(__u64 offset, char *buf, int len, void *arg)
 
 int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
 		    __u32 *version_out, char **backing_file_out,
-		    time_t *mtime_out, unsigned long long *size_out,
+		    long long *mtime_out, unsigned long long *size_out,
 		    int *sectorsize_out, __u32 *align_out,
 		    int *bitmap_offset_out)
 {
@@ -363,7 +364,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
 
 		/*
 		 * this was used until Dec2005 - 64bits are needed to represent
-		 * 2038+. I.e. we can safely do this truncating cast.
+		 * 2106+. I.e. we can safely do this truncating cast.
 		 *
 		 * Additionally, we must use be32toh() instead of be64toh(), since
 		 * the program used to use the former (tested - I got mtime
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 6627d7c30f37..dcabb463e011 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -561,7 +561,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
 	__u32 version;
 	__u32 align;
 	char *backing_file;
-	time_t mtime;
+	time64_t mtime;
 	unsigned long long size;
 	int sector_size;
 	int bitmap_offset;
@@ -600,9 +600,9 @@ static int read_cow_bitmap(int fd, void *buf, int offset, int len)
 	return 0;
 }
 
-static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
+static int backing_file_mismatch(char *file, __u64 size, time64_t mtime)
 {
-	unsigned long modtime;
+	time64_t modtime;
 	unsigned long long actual;
 	int err;
 
@@ -628,7 +628,7 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
 		return -EINVAL;
 	}
 	if (modtime != mtime) {
-		printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
+		printk(KERN_ERR "mtime mismatch (%lld vs %lld) of COW header vs "
 		       "backing file\n", mtime, modtime);
 		return -EINVAL;
 	}
@@ -671,7 +671,7 @@ static int open_ubd_file(char *file, struct openflags *openflags, int shared,
 		  unsigned long *bitmap_len_out, int *data_offset_out,
 		  int *create_cow_out)
 {
-	time_t mtime;
+	time64_t mtime;
 	unsigned long long size;
 	__u32 version, align;
 	char *backing_file;
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index 506bcd1bca68..0f30204b6afa 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -150,7 +150,7 @@ extern int os_sync_file(int fd);
 extern int os_file_size(const char *file, unsigned long long *size_out);
 extern int os_pread_file(int fd, void *buf, int len, unsigned long long offset);
 extern int os_pwrite_file(int fd, const void *buf, int count, unsigned long long offset);
-extern int os_file_modtime(const char *file, unsigned long *modtime);
+extern int os_file_modtime(const char *file, long long *modtime);
 extern int os_pipe(int *fd, int stream, int close_on_exec);
 extern int os_set_fd_async(int fd);
 extern int os_clear_fd_async(int fd);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 5133e3afb96f..fbda10535dab 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -341,7 +341,7 @@ int os_file_size(const char *file, unsigned long long *size_out)
 	return 0;
 }
 
-int os_file_modtime(const char *file, unsigned long *modtime)
+int os_file_modtime(const char *file, long long *modtime)
 {
 	struct uml_stat buf;
 	int err;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 06/24] acct: stop using get_seconds()
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (4 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 05/24] um: ubd: use 64-bit time_t where possible Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 07/24] tsacct: add 64-bit btime field Arnd Bergmann
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel
  Cc: Arnd Bergmann, Al Viro, Richard Fontana, Thomas Gleixner

In 'struct acct', 'struct acct_v3', and 'struct taskstats' we have
a 32-bit 'ac_btime' field containing an absolute time value, which
will overflow in year 2106.

There are two possible ways to deal with it:

a) let it overflow and have user space code deal with reconstructing
   the data based on the current time, or
b) truncate the times based on the range of the u32 type.

Neither of them solves the actual problem. Pick the second
one to best document what the issue is, and have someone
fix it in a future version.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/uapi/linux/acct.h      | 2 ++
 include/uapi/linux/taskstats.h | 1 +
 kernel/acct.c                  | 4 +++-
 kernel/tsacct.c                | 8 +++++---
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/acct.h b/include/uapi/linux/acct.h
index 0e72172cd23a..985b89068591 100644
--- a/include/uapi/linux/acct.h
+++ b/include/uapi/linux/acct.h
@@ -49,6 +49,7 @@ struct acct
 	__u16		ac_uid16;		/* LSB of Real User ID */
 	__u16		ac_gid16;		/* LSB of Real Group ID */
 	__u16		ac_tty;			/* Control Terminal */
+	/* __u32 range means times from 1970 to 2106 */
 	__u32		ac_btime;		/* Process Creation Time */
 	comp_t		ac_utime;		/* User Time */
 	comp_t		ac_stime;		/* System Time */
@@ -81,6 +82,7 @@ struct acct_v3
 	__u32		ac_gid;			/* Real Group ID */
 	__u32		ac_pid;			/* Process ID */
 	__u32		ac_ppid;		/* Parent Process ID */
+	/* __u32 range means times from 1970 to 2106 */
 	__u32		ac_btime;		/* Process Creation Time */
 #ifdef __KERNEL__
 	__u32		ac_etime;		/* Elapsed Time */
diff --git a/include/uapi/linux/taskstats.h b/include/uapi/linux/taskstats.h
index 5e8ca16a9079..7d3ea366e93b 100644
--- a/include/uapi/linux/taskstats.h
+++ b/include/uapi/linux/taskstats.h
@@ -112,6 +112,7 @@ struct taskstats {
 	__u32	ac_gid;			/* Group ID */
 	__u32	ac_pid;			/* Process ID */
 	__u32	ac_ppid;		/* Parent process ID */
+	/* __u32 range means times from 1970 to 2106 */
 	__u32	ac_btime;		/* Begin time [sec since 1970] */
 	__u64	ac_etime __attribute__((aligned(8)));
 					/* Elapsed time [usec] */
diff --git a/kernel/acct.c b/kernel/acct.c
index 81f9831a7859..11ff4a596d6b 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -416,6 +416,7 @@ static void fill_ac(acct_t *ac)
 {
 	struct pacct_struct *pacct = &current->signal->pacct;
 	u64 elapsed, run_time;
+	time64_t btime;
 	struct tty_struct *tty;
 
 	/*
@@ -448,7 +449,8 @@ static void fill_ac(acct_t *ac)
 	}
 #endif
 	do_div(elapsed, AHZ);
-	ac->ac_btime = get_seconds() - elapsed;
+	btime = ktime_get_real_seconds() - elapsed;
+	ac->ac_btime = clamp_t(time64_t, btime, 0, U32_MAX);
 #if ACCT_VERSION==2
 	ac->ac_ahz = AHZ;
 #endif
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 7be3e7530841..ab12616ee6fb 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -24,6 +24,7 @@ void bacct_add_tsk(struct user_namespace *user_ns,
 	const struct cred *tcred;
 	u64 utime, stime, utimescaled, stimescaled;
 	u64 delta;
+	time64_t btime;
 
 	BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN);
 
@@ -32,9 +33,10 @@ void bacct_add_tsk(struct user_namespace *user_ns,
 	/* Convert to micro seconds */
 	do_div(delta, NSEC_PER_USEC);
 	stats->ac_etime = delta;
-	/* Convert to seconds for btime */
-	do_div(delta, USEC_PER_SEC);
-	stats->ac_btime = get_seconds() - delta;
+	/* Convert to seconds for btime (note y2106 limit) */
+	btime = ktime_get_real_seconds() - div_u64(delta, USEC_PER_SEC);
+	stats->ac_btime = clamp_t(time64_t, btime, 0, U32_MAX);
+
 	if (thread_group_leader(tsk)) {
 		stats->ac_exitcode = tsk->exit_code;
 		if (tsk->flags & PF_FORKNOEXEC)
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 07/24] tsacct: add 64-bit btime field
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (5 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 06/24] acct: stop using get_seconds() Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 08/24] packet: clarify timestamp overflow Arnd Bergmann
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel; +Cc: Arnd Bergmann, Thomas Gleixner, Richard Fontana

As there is only a 32-bit ac_btime field in taskstat and
we should handle dates after the overflow, add a new field
with the same information but 64-bit width that can hold
a full time64_t.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/uapi/linux/taskstats.h | 5 ++++-
 kernel/tsacct.c                | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/taskstats.h b/include/uapi/linux/taskstats.h
index 7d3ea366e93b..ccbd08709321 100644
--- a/include/uapi/linux/taskstats.h
+++ b/include/uapi/linux/taskstats.h
@@ -34,7 +34,7 @@
  */
 
 
-#define TASKSTATS_VERSION	9
+#define TASKSTATS_VERSION	10
 #define TS_COMM_LEN		32	/* should be >= TASK_COMM_LEN
 					 * in linux/sched.h */
 
@@ -169,6 +169,9 @@ struct taskstats {
 	/* Delay waiting for thrashing page */
 	__u64	thrashing_count;
 	__u64	thrashing_delay_total;
+
+	/* v10: 64-bit btime to avoid overflow */
+	__u64	ac_btime64;		/* 64-bit begin time */
 };
 
 
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index ab12616ee6fb..257ffb993ea2 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -36,6 +36,7 @@ void bacct_add_tsk(struct user_namespace *user_ns,
 	/* Convert to seconds for btime (note y2106 limit) */
 	btime = ktime_get_real_seconds() - div_u64(delta, USEC_PER_SEC);
 	stats->ac_btime = clamp_t(time64_t, btime, 0, U32_MAX);
+	stats->ac_btime64 = btime;
 
 	if (thread_group_leader(tsk)) {
 		stats->ac_exitcode = tsk->exit_code;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 08/24] packet: clarify timestamp overflow
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (6 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 07/24] tsacct: add 64-bit btime field Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-13 20:52 ` [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition Arnd Bergmann
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel, David S. Miller
  Cc: Arnd Bergmann, Willem de Bruijn, Eric Dumazet,
	Maxim Mikityanskiy, Paolo Abeni, netdev

The memory mapped packet socket data structure in version 1 through 3
all contain 32-bit second values for the packet time stamps, which makes
them suffer from the overflow of time_t in y2038 or y2106 (depending
on whether user space interprets the value as signed or unsigned).

The implementation uses the deprecated getnstimeofday() function.

In order to get rid of that, this changes the code to use
ktime_get_real_ts64() as a replacement, documenting the nature of the
overflow. As long as the user applications treat the timestamps as
unsigned, or only use the difference between timestamps, they are
fine, and changing the timestamps to 64-bit wouldn't require a more
invasive user space API change.

Note: a lot of other APIs suffer from incompatible structures when
time_t gets redefined to 64-bit in 32-bit user space, but this one
does not.

Acked-by: Willem de Bruijn <willemb@google.com>
Link: https://lore.kernel.org/lkml/CAF=yD-Jomr-gWSR-EBNKnSpFL46UeG564FLfqTCMNEm-prEaXA@mail.gmail.com/T/#u
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 net/packet/af_packet.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 53c1d41fb1c9..60300f3fcddc 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -408,17 +408,17 @@ static int __packet_get_status(const struct packet_sock *po, void *frame)
 	}
 }
 
-static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
+static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec64 *ts,
 				   unsigned int flags)
 {
 	struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 
 	if (shhwtstamps &&
 	    (flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
-	    ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+	    ktime_to_timespec64_cond(shhwtstamps->hwtstamp, ts))
 		return TP_STATUS_TS_RAW_HARDWARE;
 
-	if (ktime_to_timespec_cond(skb->tstamp, ts))
+	if (ktime_to_timespec64_cond(skb->tstamp, ts))
 		return TP_STATUS_TS_SOFTWARE;
 
 	return 0;
@@ -428,13 +428,20 @@ static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
 				    struct sk_buff *skb)
 {
 	union tpacket_uhdr h;
-	struct timespec ts;
+	struct timespec64 ts;
 	__u32 ts_status;
 
 	if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
 		return 0;
 
 	h.raw = frame;
+	/*
+	 * versions 1 through 3 overflow the timestamps in y2106, since they
+	 * all store the seconds in a 32-bit unsigned integer.
+	 * If we create a version 4, that should have a 64-bit timestamp,
+	 * either 64-bit seconds + 32-bit nanoseconds, or just 64-bit
+	 * nanoseconds.
+	 */
 	switch (po->tp_version) {
 	case TPACKET_V1:
 		h.h1->tp_sec = ts.tv_sec;
@@ -774,8 +781,8 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
 		 * It shouldn't really happen as we don't close empty
 		 * blocks. See prb_retire_rx_blk_timer_expired().
 		 */
-		struct timespec ts;
-		getnstimeofday(&ts);
+		struct timespec64 ts;
+		ktime_get_real_ts64(&ts);
 		h1->ts_last_pkt.ts_sec = ts.tv_sec;
 		h1->ts_last_pkt.ts_nsec	= ts.tv_nsec;
 	}
@@ -805,7 +812,7 @@ static void prb_thaw_queue(struct tpacket_kbdq_core *pkc)
 static void prb_open_block(struct tpacket_kbdq_core *pkc1,
 	struct tpacket_block_desc *pbd1)
 {
-	struct timespec ts;
+	struct timespec64 ts;
 	struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
 
 	smp_rmb();
@@ -818,7 +825,7 @@ static void prb_open_block(struct tpacket_kbdq_core *pkc1,
 	BLOCK_NUM_PKTS(pbd1) = 0;
 	BLOCK_LEN(pbd1) = BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
 
-	getnstimeofday(&ts);
+	ktime_get_real_ts64(&ts);
 
 	h1->ts_first_pkt.ts_sec = ts.tv_sec;
 	h1->ts_first_pkt.ts_nsec = ts.tv_nsec;
@@ -2168,7 +2175,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 	unsigned long status = TP_STATUS_USER;
 	unsigned short macoff, netoff, hdrlen;
 	struct sk_buff *copy_skb = NULL;
-	struct timespec ts;
+	struct timespec64 ts;
 	__u32 ts_status;
 	bool is_drop_n_account = false;
 	bool do_vnet = false;
@@ -2300,7 +2307,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 	skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
 
 	if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
-		getnstimeofday(&ts);
+		ktime_get_real_ts64(&ts);
 
 	status |= ts_status;
 
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (7 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 08/24] packet: clarify timestamp overflow Arnd Bergmann
@ 2019-12-13 20:52 ` Arnd Bergmann
  2019-12-16 13:14   ` Jan Kara
  2019-12-13 20:53 ` [PATCH v2 10/24] hostfs: pass 64-bit timestamps to/from user space Arnd Bergmann
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:52 UTC (permalink / raw)
  To: y2038, linux-kernel, Jan Kara; +Cc: Arnd Bergmann

The time_t type is part of the user interface and not always the
same, with the move to 64-bit timestamps and the difference between
architectures.

Make the quota format definition independent of this type and use
a basic type of the same length. Make it unsigned in the process
to keep the v1 format working until year 2106 instead of 2038
on 32-bit architectures.

Hopefully, everybody has already moved to a newer format long
ago (v2 was introduced with linux-2.4), but it's hard to be sure.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/quota/quotaio_v1.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/fs/quota/quotaio_v1.h b/fs/quota/quotaio_v1.h
index bd11e2c08119..31dca9a89176 100644
--- a/fs/quota/quotaio_v1.h
+++ b/fs/quota/quotaio_v1.h
@@ -25,8 +25,10 @@ struct v1_disk_dqblk {
 	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
 	__u32 dqb_isoftlimit;	/* preferred inode limit */
 	__u32 dqb_curinodes;	/* current # allocated inodes */
-	time_t dqb_btime;	/* time limit for excessive disk use */
-	time_t dqb_itime;	/* time limit for excessive inode use */
+
+	/* below fields differ in length on 32-bit vs 64-bit architectures */
+	unsigned long dqb_btime; /* time limit for excessive disk use */
+	unsigned long dqb_itime; /* time limit for excessive inode use */
 };
 
 #define v1_dqoff(UID)      ((loff_t)((UID) * sizeof (struct v1_disk_dqblk)))
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 10/24] hostfs: pass 64-bit timestamps to/from user space
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (8 preceding siblings ...)
  2019-12-13 20:52 ` [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 11/24] hfs/hfsplus: use 64-bit inode timestamps Arnd Bergmann
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Jeff Dike, Richard Weinberger, Anton Ivanov
  Cc: Arnd Bergmann, linux-um

The use of 'struct timespec' is deprecated in the kernel, so we
want to avoid the conversions from/to the proper timespec64
structure.

On the user space side, we have a 'struct timespec' that is defined
by the C library and that will be incompatible with the kernel's
view on 32-bit architectures once they move to a 64-bit time_t,
breaking the shared binary layout of hostfs_iattr and hostfs_stat.

This changes the two structures to use a new hostfs_timespec structure
with fixed 64-bit seconds/nanoseconds for passing the timestamps
between hostfs_kern.c and hostfs_user.c. With a new enough user
space side, this will allow timestamps beyond year 2038.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/hostfs/hostfs.h      | 22 +++++++++++++---------
 fs/hostfs/hostfs_kern.c | 15 +++++++++------
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index f4295aa19350..69cb796f6270 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -37,16 +37,20 @@
  * is on, and remove the appropriate bits from attr->ia_mode (attr is a
  * "struct iattr *"). -BlaisorBlade
  */
+struct hostfs_timespec {
+	long long tv_sec;
+	long long tv_nsec;
+};
 
 struct hostfs_iattr {
-	unsigned int	ia_valid;
-	unsigned short	ia_mode;
-	uid_t		ia_uid;
-	gid_t		ia_gid;
-	loff_t		ia_size;
-	struct timespec	ia_atime;
-	struct timespec	ia_mtime;
-	struct timespec	ia_ctime;
+	unsigned int		ia_valid;
+	unsigned short		ia_mode;
+	uid_t			ia_uid;
+	gid_t			ia_gid;
+	loff_t			ia_size;
+	struct hostfs_timespec	ia_atime;
+	struct hostfs_timespec	ia_mtime;
+	struct hostfs_timespec	ia_ctime;
 };
 
 struct hostfs_stat {
@@ -56,7 +60,7 @@ struct hostfs_stat {
 	unsigned int uid;
 	unsigned int gid;
 	unsigned long long size;
-	struct timespec atime, mtime, ctime;
+	struct hostfs_timespec atime, mtime, ctime;
 	unsigned int blksize;
 	unsigned long long blocks;
 	unsigned int maj;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 5a7eb0c79839..e6b8c49076bb 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -549,9 +549,9 @@ static int read_name(struct inode *ino, char *name)
 	set_nlink(ino, st.nlink);
 	i_uid_write(ino, st.uid);
 	i_gid_write(ino, st.gid);
-	ino->i_atime = timespec_to_timespec64(st.atime);
-	ino->i_mtime = timespec_to_timespec64(st.mtime);
-	ino->i_ctime = timespec_to_timespec64(st.ctime);
+	ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
+	ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
+	ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
 	ino->i_size = st.size;
 	ino->i_blocks = st.blocks;
 	return 0;
@@ -820,15 +820,18 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
 	}
 	if (attr->ia_valid & ATTR_ATIME) {
 		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
-		attrs.ia_atime = timespec64_to_timespec(attr->ia_atime);
+		attrs.ia_atime = (struct hostfs_timespec)
+			{ attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec };
 	}
 	if (attr->ia_valid & ATTR_MTIME) {
 		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
-		attrs.ia_mtime = timespec64_to_timespec(attr->ia_mtime);
+		attrs.ia_mtime = (struct hostfs_timespec)
+			{ attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec };
 	}
 	if (attr->ia_valid & ATTR_CTIME) {
 		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
-		attrs.ia_ctime = timespec64_to_timespec(attr->ia_ctime);
+		attrs.ia_ctime = (struct hostfs_timespec)
+			{ attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec };
 	}
 	if (attr->ia_valid & ATTR_ATIME_SET) {
 		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 11/24] hfs/hfsplus: use 64-bit inode timestamps
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (9 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 10/24] hostfs: pass 64-bit timestamps to/from user space Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 12/24] drm/msm: avoid using 'timespec' Arnd Bergmann
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel
  Cc: Arnd Bergmann, Ernesto A. Fernández, Vyacheslav Dubeyko,
	Andrew Morton, linux-fsdevel

The interpretation of on-disk timestamps in HFS and HFS+ differs
between 32-bit and 64-bit kernels at the moment. Use 64-bit timestamps
consistently so apply the current 64-bit behavior everyhere.

According to the official documentation for HFS+ [1], inode timestamps
are supposed to cover the time range from 1904 to 2040 as originally
used in classic MacOS.

The traditional Linux usage is to convert the timestamps into an unsigned
32-bit number based on the Unix epoch and from there to a time_t. On
32-bit systems, that wraps the time from 2038 to 1902, so the last
two years of the valid time range become garbled. On 64-bit systems,
all times before 1970 get turned into timestamps between 2038 and 2106,
which is more convenient but also different from the documented behavior.

Looking at the Darwin sources [2], it seems that MacOS is inconsistent in
yet another way: all timestamps are wrapped around to a 32-bit unsigned
number when written to the disk, but when read back, all numeric values
lower than 2082844800U are assumed to be invalid, so we cannot represent
the times before 1970 or the times after 2040.

While all implementations seem to agree on the interpretation of values
between 1970 and 2038, they often differ on the exact range they support
when reading back values outside of the common range:

MacOS (traditional):		1904-2040
Apple Documentation:		1904-2040
MacOS X source comments:	1970-2040
MacOS X source code:		1970-2038
32-bit Linux:			1902-2038
64-bit Linux:			1970-2106
hfsfuse:			1970-2040
hfsutils (32 bit, old libc)	1902-2038
hfsutils (32 bit, new libc)	1970-2106
hfsutils (64 bit)		1904-2040
hfsplus-utils			1904-2040
hfsexplorer			1904-2040
7-zip				1904-2040

Out of the above, the range from 1970 to 2106 seems to be the most useful,
as it allows using HFS and HFS+ beyond year 2038, and this matches the
behavior that most users would see today on Linux, as few people run
32-bit kernels any more.

Link: [1] https://developer.apple.com/library/archive/technotes/tn/tn1150.html
Link: [2] https://opensource.apple.com/source/hfs/hfs-407.30.1/core/MacOSStubs.c.auto.html
Link: https://lore.kernel.org/lkml/20180711224625.airwna6gzyatoowe@eaf/
Suggested-by: "Ernesto A. Fernández" <ernesto.mnd.fernandez@gmail.com>
Reviewed-by: Vyacheslav Dubeyko <slava@dubeyko.com>
Reviewed-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
v3: revert back to 1970-2106 time range
    fix bugs found in review
    merge both patches into one
    drop cc:stable tag
v2: treat pre-1970 dates as invalid following MacOS X behavior,
    reword and expand changelog text
---
 fs/hfs/hfs_fs.h         | 28 ++++++++++++++++++++++------
 fs/hfs/inode.c          |  4 ++--
 fs/hfsplus/hfsplus_fs.h | 28 +++++++++++++++++++++++-----
 fs/hfsplus/inode.c      | 12 ++++++------
 4 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 6d0783e2e276..f71c384064c8 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -242,19 +242,35 @@ extern void hfs_mark_mdb_dirty(struct super_block *sb);
 /*
  * There are two time systems.  Both are based on seconds since
  * a particular time/date.
- *	Unix:	unsigned lil-endian since 00:00 GMT, Jan. 1, 1970
+ *	Unix:	signed little-endian since 00:00 GMT, Jan. 1, 1970
  *	mac:	unsigned big-endian since 00:00 GMT, Jan. 1, 1904
  *
+ * HFS implementations are highly inconsistent, this one matches the
+ * traditional behavior of 64-bit Linux, giving the most useful
+ * time range between 1970 and 2106, by treating any on-disk timestamp
+ * under HFS_UTC_OFFSET (Jan 1 1970) as a time between 2040 and 2106.
  */
-#define __hfs_u_to_mtime(sec)	cpu_to_be32(sec + 2082844800U - sys_tz.tz_minuteswest * 60)
-#define __hfs_m_to_utime(sec)	(be32_to_cpu(sec) - 2082844800U  + sys_tz.tz_minuteswest * 60)
+#define HFS_UTC_OFFSET 2082844800U
 
+static inline time64_t __hfs_m_to_utime(__be32 mt)
+{
+	time64_t ut = (u32)(be32_to_cpu(mt) - HFS_UTC_OFFSET);
+
+	return ut + sys_tz.tz_minuteswest * 60;
+}
+
+static inline __be32 __hfs_u_to_mtime(time64_t ut)
+{
+	ut -= sys_tz.tz_minuteswest * 60;
+
+	return cpu_to_be32(lower_32_bits(ut) + HFS_UTC_OFFSET);
+}
 #define HFS_I(inode)	(container_of(inode, struct hfs_inode_info, vfs_inode))
 #define HFS_SB(sb)	((struct hfs_sb_info *)(sb)->s_fs_info)
 
-#define hfs_m_to_utime(time)	(struct timespec){ .tv_sec = __hfs_m_to_utime(time) }
-#define hfs_u_to_mtime(time)	__hfs_u_to_mtime((time).tv_sec)
-#define hfs_mtime()		__hfs_u_to_mtime(get_seconds())
+#define hfs_m_to_utime(time)   (struct timespec64){ .tv_sec = __hfs_m_to_utime(time) }
+#define hfs_u_to_mtime(time)   __hfs_u_to_mtime((time).tv_sec)
+#define hfs_mtime()		__hfs_u_to_mtime(ktime_get_real_seconds())
 
 static inline const char *hfs_mdb_name(struct super_block *sb)
 {
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index da243c84e93b..2f224b98ee94 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -351,7 +351,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		inode->i_mode &= ~hsb->s_file_umask;
 		inode->i_mode |= S_IFREG;
 		inode->i_ctime = inode->i_atime = inode->i_mtime =
-				timespec_to_timespec64(hfs_m_to_utime(rec->file.MdDat));
+				hfs_m_to_utime(rec->file.MdDat);
 		inode->i_op = &hfs_file_inode_operations;
 		inode->i_fop = &hfs_file_operations;
 		inode->i_mapping->a_ops = &hfs_aops;
@@ -362,7 +362,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		HFS_I(inode)->fs_blocks = 0;
 		inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
 		inode->i_ctime = inode->i_atime = inode->i_mtime =
-				timespec_to_timespec64(hfs_m_to_utime(rec->dir.MdDat));
+				hfs_m_to_utime(rec->dir.MdDat);
 		inode->i_op = &hfs_dir_inode_operations;
 		inode->i_fop = &hfs_dir_operations;
 		break;
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index b8471bf05def..3b03fff68543 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -533,13 +533,31 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, void *buf,
 		       void **data, int op, int op_flags);
 int hfsplus_read_wrapper(struct super_block *sb);
 
-/* time macros */
-#define __hfsp_mt2ut(t)		(be32_to_cpu(t) - 2082844800U)
-#define __hfsp_ut2mt(t)		(cpu_to_be32(t + 2082844800U))
+/*
+ * time helpers: convert between 1904-base and 1970-base timestamps
+ *
+ * HFS+ implementations are highly inconsistent, this one matches the
+ * traditional behavior of 64-bit Linux, giving the most useful
+ * time range between 1970 and 2106, by treating any on-disk timestamp
+ * under HFSPLUS_UTC_OFFSET (Jan 1 1970) as a time between 2040 and 2106.
+ */
+#define HFSPLUS_UTC_OFFSET 2082844800U
+
+static inline time64_t __hfsp_mt2ut(__be32 mt)
+{
+	time64_t ut = (u32)(be32_to_cpu(mt) - HFSPLUS_UTC_OFFSET);
+
+	return ut;
+}
+
+static inline __be32 __hfsp_ut2mt(time64_t ut)
+{
+	return cpu_to_be32(lower_32_bits(ut) + HFSPLUS_UTC_OFFSET);
+}
 
 /* compatibility */
-#define hfsp_mt2ut(t)		(struct timespec){ .tv_sec = __hfsp_mt2ut(t) }
+#define hfsp_mt2ut(t)		(struct timespec64){ .tv_sec = __hfsp_mt2ut(t) }
 #define hfsp_ut2mt(t)		__hfsp_ut2mt((t).tv_sec)
-#define hfsp_now2mt()		__hfsp_ut2mt(get_seconds())
+#define hfsp_now2mt()		__hfsp_ut2mt(ktime_get_real_seconds())
 
 #endif
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index d131c8ea7eb6..94bd83b36644 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -504,9 +504,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 		hfsplus_get_perms(inode, &folder->permissions, 1);
 		set_nlink(inode, 1);
 		inode->i_size = 2 + be32_to_cpu(folder->valence);
-		inode->i_atime = timespec_to_timespec64(hfsp_mt2ut(folder->access_date));
-		inode->i_mtime = timespec_to_timespec64(hfsp_mt2ut(folder->content_mod_date));
-		inode->i_ctime = timespec_to_timespec64(hfsp_mt2ut(folder->attribute_mod_date));
+		inode->i_atime = hfsp_mt2ut(folder->access_date);
+		inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
+		inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
 		HFSPLUS_I(inode)->create_date = folder->create_date;
 		HFSPLUS_I(inode)->fs_blocks = 0;
 		if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
@@ -542,9 +542,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 			init_special_inode(inode, inode->i_mode,
 					   be32_to_cpu(file->permissions.dev));
 		}
-		inode->i_atime = timespec_to_timespec64(hfsp_mt2ut(file->access_date));
-		inode->i_mtime = timespec_to_timespec64(hfsp_mt2ut(file->content_mod_date));
-		inode->i_ctime = timespec_to_timespec64(hfsp_mt2ut(file->attribute_mod_date));
+		inode->i_atime = hfsp_mt2ut(file->access_date);
+		inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
+		inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
 		HFSPLUS_I(inode)->create_date = file->create_date;
 	} else {
 		pr_err("bad catalog entry used to create inode\n");
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 12/24] drm/msm: avoid using 'timespec'
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (10 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 11/24] hfs/hfsplus: use 64-bit inode timestamps Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC Arnd Bergmann
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Rob Clark, Sean Paul, David Airlie, Daniel Vetter
  Cc: Arnd Bergmann, Jordan Crouse, Jeykumar Sankaran, Sam Ravnborg,
	Joe Perches, Kristian H. Kristensen, Thomas Gleixner,
	linux-arm-msm, dri-devel, freedreno

The timespec structure and associated interfaces are deprecated and will
be removed in the future because of the y2038 overflow.

The use of ktime_to_timespec() in timeout_to_jiffies() does not
suffer from that overflow, but is easy to avoid by just converting
the ktime_t into jiffies directly.

Reviewed-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/gpu/drm/msm/msm_drv.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 71547e756e29..740bf7c70d8f 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -454,8 +454,7 @@ static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)
 		remaining_jiffies = 0;
 	} else {
 		ktime_t rem = ktime_sub(*timeout, now);
-		struct timespec ts = ktime_to_timespec(rem);
-		remaining_jiffies = timespec_to_jiffies(&ts);
+		remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ);
 	}
 
 	return remaining_jiffies;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (11 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 12/24] drm/msm: avoid using 'timespec' Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2020-01-08  1:16   ` [Y2038] " Ben Hutchings
  2020-01-17 15:47   ` Guido Günther
  2019-12-13 20:53 ` [PATCH v2 14/24] drm/etnaviv: avoid deprecated timespec Arnd Bergmann
                   ` (10 subsequent siblings)
  23 siblings, 2 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Lucas Stach, David Airlie, Daniel Vetter
  Cc: Arnd Bergmann, Russell King, Christian Gmeiner,
	Guido Günther, Philipp Zabel, Emil Velikov, Sam Ravnborg,
	etnaviv, dri-devel

Most kernel interfaces that take a timespec require normalized
representation with tv_nsec between 0 and NSEC_PER_SEC.

Passing values larger than 0x100000000ull further behaves differently
on 32-bit and 64-bit kernels, and can cause the latter to spend a long
time counting seconds in timespec64_sub()/set_normalized_timespec64().

Reject those large values at the user interface to enforce sane and
portable behavior.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 1f9c01be40d7..95d72dc00280 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -297,6 +297,9 @@ static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
 		return -EINVAL;
 
+	if (args->timeout.tv_nsec > NSEC_PER_SEC)
+		return -EINVAL;
+
 	obj = drm_gem_object_lookup(file, args->handle);
 	if (!obj)
 		return -ENOENT;
@@ -360,6 +363,9 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
 		return -EINVAL;
 
+	if (args->timeout.tv_nsec > NSEC_PER_SEC)
+		return -EINVAL;
+
 	if (args->pipe >= ETNA_MAX_PIPES)
 		return -EINVAL;
 
@@ -411,6 +417,9 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
 		return -EINVAL;
 
+	if (args->timeout.tv_nsec > NSEC_PER_SEC)
+		return -EINVAL;
+
 	if (args->pipe >= ETNA_MAX_PIPES)
 		return -EINVAL;
 
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 14/24] drm/etnaviv: avoid deprecated timespec
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (12 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 15/24] sunrpc: convert to time64_t for expiry Arnd Bergmann
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Lucas Stach, David Airlie, Daniel Vetter
  Cc: Arnd Bergmann, Russell King, Christian Gmeiner, Philipp Zabel,
	Guido Günther, etnaviv, dri-devel

struct timespec is being removed from the kernel because it often leads
to code that is not y2038-safe.

In the etnaviv driver, monotonic timestamps are used, which do not suffer
from overflow, but the usage of timespec here gets in the way of removing
the interface completely.

Pass down the user-supplied 64-bit value here rather than converting
it to an intermediate timespec to avoid the conversion.

The conversion is transparent for all regular CLOCK_MONOTONIC values,
but is a small change in behavior for excessively large values: the
existing code would treat e.g. tv_sec=0x100000000 the same as tv_sec=0
and not block, while the new code it would block for up to 2^31
seconds. The new behavior is more logical here, but if it causes problems,
the truncation can be put back.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 11 +++--------
 drivers/gpu/drm/etnaviv/etnaviv_drv.h | 11 ++++++-----
 drivers/gpu/drm/etnaviv/etnaviv_gem.c |  4 ++--
 drivers/gpu/drm/etnaviv/etnaviv_gem.h |  2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c |  5 +++--
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |  5 +++--
 6 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 95d72dc00280..3eb0f9223bea 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -282,11 +282,6 @@ static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
 			args->flags, &args->handle);
 }
 
-#define TS(t) ((struct timespec){ \
-	.tv_sec = (t).tv_sec, \
-	.tv_nsec = (t).tv_nsec \
-})
-
 static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 		struct drm_file *file)
 {
@@ -304,7 +299,7 @@ static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 	if (!obj)
 		return -ENOENT;
 
-	ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+	ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout);
 
 	drm_gem_object_put_unlocked(obj);
 
@@ -357,7 +352,7 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
 {
 	struct drm_etnaviv_wait_fence *args = data;
 	struct etnaviv_drm_private *priv = dev->dev_private;
-	struct timespec *timeout = &TS(args->timeout);
+	struct drm_etnaviv_timespec *timeout = &args->timeout;
 	struct etnaviv_gpu *gpu;
 
 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
@@ -409,7 +404,7 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
 {
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_etnaviv_gem_wait *args = data;
-	struct timespec *timeout = &TS(args->timeout);
+	struct drm_etnaviv_timespec *timeout = &args->timeout;
 	struct drm_gem_object *obj;
 	struct etnaviv_gpu *gpu;
 	int ret;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 32cfa5a48d42..efc656efeb0f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -61,7 +61,7 @@ int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
 void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
 void *etnaviv_gem_vmap(struct drm_gem_object *obj);
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
-		struct timespec *timeout);
+		struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
 void etnaviv_gem_free_object(struct drm_gem_object *obj);
 int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
@@ -107,11 +107,12 @@ static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base)
  * between the specified timeout and the current CLOCK_MONOTONIC time.
  */
 static inline unsigned long etnaviv_timeout_to_jiffies(
-	const struct timespec *timeout)
+	const struct drm_etnaviv_timespec *timeout)
 {
-	struct timespec64 ts, to;
-
-	to = timespec_to_timespec64(*timeout);
+	struct timespec64 ts, to = {
+		.tv_sec = timeout->tv_sec,
+		.tv_nsec = timeout->tv_nsec,
+	};
 
 	ktime_get_ts64(&ts);
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index cb1faaac380a..6adea180d629 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -373,7 +373,7 @@ static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
 }
 
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
-		struct timespec *timeout)
+		struct drm_etnaviv_timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 	struct drm_device *dev = obj->dev;
@@ -431,7 +431,7 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
 }
 
 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	struct timespec *timeout)
+	struct drm_etnaviv_timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index d6270acce619..6b68fe16041b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -112,7 +112,7 @@ struct etnaviv_gem_submit {
 void etnaviv_submit_put(struct etnaviv_gem_submit * submit);
 
 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	struct timespec *timeout);
+	struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
 	const struct etnaviv_gem_ops *ops, struct etnaviv_gem_object **res);
 void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index d47d1a8e0219..799ec20b267d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1132,7 +1132,7 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
  * Cmdstream submission/retirement:
  */
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	u32 id, struct timespec *timeout)
+	u32 id, struct drm_etnaviv_timespec *timeout)
 {
 	struct dma_fence *fence;
 	int ret;
@@ -1179,7 +1179,8 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
  * that lock in this function while waiting.
  */
 int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
+	struct etnaviv_gem_object *etnaviv_obj,
+	struct drm_etnaviv_timespec *timeout)
 {
 	unsigned long remaining;
 	long ret;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 8f9bd4edc96a..97bb48042b4d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -169,9 +169,10 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	u32 fence, struct timespec *timeout);
+	u32 fence, struct drm_etnaviv_timespec *timeout);
 int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
+	struct etnaviv_gem_object *etnaviv_obj,
+	struct drm_etnaviv_timespec *timeout);
 struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 15/24] sunrpc: convert to time64_t for expiry
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (13 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 14/24] drm/etnaviv: avoid deprecated timespec Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 16/24] nfs: use time64_t internally Arnd Bergmann
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, J. Bruce Fields, Chuck Lever,
	Trond Myklebust, Anna Schumaker, David S. Miller
  Cc: Arnd Bergmann, Simo Sorce, Eric Biggers, Herbert Xu,
	Bruce Fields, linux-nfs, netdev

Using signed 32-bit types for UTC time leads to the y2038 overflow,
which is what happens in the sunrpc code at the moment.

This changes the sunrpc code over to use time64_t where possible.
The one exception is the gss_import_v{1,2}_context() function for
kerberos5, which uses 32-bit timestamps in the protocol. Here,
we can at least treat the numbers as 'unsigned', which extends the
range from 2038 to 2106.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/linux/sunrpc/gss_api.h        |  4 ++--
 include/linux/sunrpc/gss_krb5.h       |  2 +-
 net/sunrpc/auth_gss/gss_krb5_mech.c   | 12 +++++++++---
 net/sunrpc/auth_gss/gss_krb5_seal.c   |  8 ++++----
 net/sunrpc/auth_gss/gss_krb5_unseal.c |  6 +++---
 net/sunrpc/auth_gss/gss_krb5_wrap.c   | 16 ++++++++--------
 net/sunrpc/auth_gss/gss_mech_switch.c |  2 +-
 net/sunrpc/auth_gss/svcauth_gss.c     |  4 ++--
 8 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index bd691e08be3b..1cc6cefb1220 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -48,7 +48,7 @@ int gss_import_sec_context(
 		size_t			bufsize,
 		struct gss_api_mech	*mech,
 		struct gss_ctx		**ctx_id,
-		time_t			*endtime,
+		time64_t		*endtime,
 		gfp_t			gfp_mask);
 u32 gss_get_mic(
 		struct gss_ctx		*ctx_id,
@@ -108,7 +108,7 @@ struct gss_api_ops {
 			const void		*input_token,
 			size_t			bufsize,
 			struct gss_ctx		*ctx_id,
-			time_t			*endtime,
+			time64_t		*endtime,
 			gfp_t			gfp_mask);
 	u32 (*gss_get_mic)(
 			struct gss_ctx		*ctx_id,
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 02c0412e368c..c1d77dd8ed41 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -106,9 +106,9 @@ struct krb5_ctx {
 	struct crypto_sync_skcipher *initiator_enc_aux;
 	u8			Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */
 	u8			cksum[GSS_KRB5_MAX_KEYLEN];
-	s32			endtime;
 	atomic_t		seq_send;
 	atomic64_t		seq_send64;
+	time64_t		endtime;
 	struct xdr_netobj	mech_used;
 	u8			initiator_sign[GSS_KRB5_MAX_KEYLEN];
 	u8			acceptor_sign[GSS_KRB5_MAX_KEYLEN];
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 6e5d6d240215..75b3c2e9e8f8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -253,6 +253,7 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
 {
 	u32 seq_send;
 	int tmp;
+	u32 time32;
 
 	p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
 	if (IS_ERR(p))
@@ -290,9 +291,11 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
 		p = ERR_PTR(-ENOSYS);
 		goto out_err;
 	}
-	p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
+	p = simple_get_bytes(p, end, &time32, sizeof(time32));
 	if (IS_ERR(p))
 		goto out_err;
+	/* unsigned 32-bit time overflows in year 2106 */
+	ctx->endtime = (time64_t)time32;
 	p = simple_get_bytes(p, end, &seq_send, sizeof(seq_send));
 	if (IS_ERR(p))
 		goto out_err;
@@ -587,15 +590,18 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
 {
 	u64 seq_send64;
 	int keylen;
+	u32 time32;
 
 	p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
 	if (IS_ERR(p))
 		goto out_err;
 	ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
 
-	p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
+	p = simple_get_bytes(p, end, &time32, sizeof(time32));
 	if (IS_ERR(p))
 		goto out_err;
+	/* unsigned 32-bit time overflows in year 2106 */
+	ctx->endtime = (time64_t)time32;
 	p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64));
 	if (IS_ERR(p))
 		goto out_err;
@@ -659,7 +665,7 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
 static int
 gss_import_sec_context_kerberos(const void *p, size_t len,
 				struct gss_ctx *ctx_id,
-				time_t *endtime,
+				time64_t *endtime,
 				gfp_t gfp_mask)
 {
 	const void *end = (const void *)((const char *)p + len);
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 48fe4a591b54..f1d280accf43 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -131,14 +131,14 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
 	struct xdr_netobj	md5cksum = {.len = sizeof(cksumdata),
 					    .data = cksumdata};
 	void			*ptr;
-	s32			now;
+	time64_t		now;
 	u32			seq_send;
 	u8			*cksumkey;
 
 	dprintk("RPC:       %s\n", __func__);
 	BUG_ON(ctx == NULL);
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	ptr = setup_token(ctx, token);
 
@@ -170,7 +170,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 	struct xdr_netobj cksumobj = { .len = sizeof(cksumdata),
 				       .data = cksumdata};
 	void *krb5_hdr;
-	s32 now;
+	time64_t now;
 	u8 *cksumkey;
 	unsigned int cksum_usage;
 	__be64 seq_send_be64;
@@ -198,7 +198,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 
 	memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len);
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index ef2b25b86d2f..aaab91cf24c8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -124,7 +124,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
 
 	/* it got through unscathed.  Make sure the context is unexpired */
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	if (now > ctx->endtime)
 		return GSS_S_CONTEXT_EXPIRED;
@@ -149,7 +149,7 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
 	char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
 	struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
 				      .data = cksumdata};
-	s32 now;
+	time64_t now;
 	u8 *ptr = read_token->data;
 	u8 *cksumkey;
 	u8 flags;
@@ -194,7 +194,7 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
 		return GSS_S_BAD_SIG;
 
 	/* it got through unscathed.  Make sure the context is unexpired */
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	if (now > ctx->endtime)
 		return GSS_S_CONTEXT_EXPIRED;
 
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 14a0aff0cd84..6c1920eed771 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -163,7 +163,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
 					    .data = cksumdata};
 	int			blocksize = 0, plainlen;
 	unsigned char		*ptr, *msg_start;
-	s32			now;
+	time64_t		now;
 	int			headlen;
 	struct page		**tmp_pages;
 	u32			seq_send;
@@ -172,7 +172,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
 
 	dprintk("RPC:       %s\n", __func__);
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	blocksize = crypto_sync_skcipher_blocksize(kctx->enc);
 	gss_krb5_add_padding(buf, offset, blocksize);
@@ -268,7 +268,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
 	char			cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
 	struct xdr_netobj	md5cksum = {.len = sizeof(cksumdata),
 					    .data = cksumdata};
-	s32			now;
+	time64_t		now;
 	int			direction;
 	s32			seqnum;
 	unsigned char		*ptr;
@@ -359,7 +359,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
 
 	/* it got through unscathed.  Make sure the context is unexpired */
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	if (now > kctx->endtime)
 		return GSS_S_CONTEXT_EXPIRED;
@@ -439,7 +439,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
 		     struct xdr_buf *buf, struct page **pages)
 {
 	u8		*ptr, *plainhdr;
-	s32		now;
+	time64_t	now;
 	u8		flags = 0x00;
 	__be16		*be16ptr;
 	__be64		*be64ptr;
@@ -481,14 +481,14 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
 	if (err)
 		return err;
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
 
 static u32
 gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
 {
-	s32		now;
+	time64_t	now;
 	u8		*ptr;
 	u8		flags = 0x00;
 	u16		ec, rrc;
@@ -557,7 +557,7 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
 	/* do sequencing checks */
 
 	/* it got through unscathed.  Make sure the context is unexpired */
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	if (now > kctx->endtime)
 		return GSS_S_CONTEXT_EXPIRED;
 
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 30b7de6f3d76..d3685d4ed9e0 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -376,7 +376,7 @@ int
 gss_import_sec_context(const void *input_token, size_t bufsize,
 		       struct gss_api_mech	*mech,
 		       struct gss_ctx		**ctx_id,
-		       time_t			*endtime,
+		       time64_t			*endtime,
 		       gfp_t gfp_mask)
 {
 	if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask)))
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index c62d1f10978b..0c3e22838ddf 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -436,7 +436,7 @@ static int rsc_parse(struct cache_detail *cd,
 	int id;
 	int len, rv;
 	struct rsc rsci, *rscp = NULL;
-	time_t expiry;
+	time64_t expiry;
 	int status = -EINVAL;
 	struct gss_api_mech *gm = NULL;
 
@@ -1221,7 +1221,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
 	static atomic64_t ctxhctr;
 	long long ctxh;
 	struct gss_api_mech *gm = NULL;
-	time_t expiry;
+	time64_t expiry;
 	int status = -EINVAL;
 
 	memset(&rsci, 0, sizeof(rsci));
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 16/24] nfs: use time64_t internally
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (14 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 15/24] sunrpc: convert to time64_t for expiry Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 17/24] nfs: fix timstamp debug prints Arnd Bergmann
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, J. Bruce Fields, Chuck Lever,
	Trond Myklebust, Anna Schumaker, David S. Miller
  Cc: Arnd Bergmann, Thomas Gleixner, Jeff Layton, linux-nfs, netdev

The timestamps for the cache are all in boottime seconds, so they
don't overflow 32-bit values, but the use of time_t is deprecated
because it generally does overflow when used with wall-clock time.

There are multiple possible ways of avoiding it:

- leave time_t, which is safe here, but forces others to
  look into this code to determine that it is over and over.

- use a more generic type, like 'int' or 'long', which is known
  to be sufficient here but loses the documentation of referring
  to timestamps

- use ktime_t everywhere, and convert into seconds in the few
  places where we want realtime-seconds. The conversion is
  sometimes expensive, but not more so than the conversion we
  do today.

- use time64_t to clarify that this code is safe. Nothing would
  change for 64-bit architectures, but it is slightly less
  efficient on 32-bit architectures.

Without a clear winner of the three approaches above, this picks
the last one, favouring readability over a small performance
loss on 32-bit architectures.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/linux/sunrpc/cache.h      | 42 +++++++++++++++++--------------
 net/sunrpc/auth_gss/svcauth_gss.c |  2 +-
 net/sunrpc/cache.c                | 16 ++++++------
 net/sunrpc/svcauth_unix.c         | 10 ++++----
 4 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index f8603724fbee..0f64de7caa39 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -45,8 +45,8 @@
  */
 struct cache_head {
 	struct hlist_node	cache_list;
-	time_t		expiry_time;	/* After time time, don't use the data */
-	time_t		last_refresh;   /* If CACHE_PENDING, this is when upcall was
+	time64_t	expiry_time;	/* After time time, don't use the data */
+	time64_t	last_refresh;   /* If CACHE_PENDING, this is when upcall was
 					 * sent, else this is when update was
 					 * received, though it is alway set to
 					 * be *after* ->flush_time.
@@ -95,22 +95,22 @@ struct cache_detail {
 	/* fields below this comment are for internal use
 	 * and should not be touched by cache owners
 	 */
-	time_t			flush_time;		/* flush all cache items with
+	time64_t		flush_time;		/* flush all cache items with
 							 * last_refresh at or earlier
 							 * than this.  last_refresh
 							 * is never set at or earlier
 							 * than this.
 							 */
 	struct list_head	others;
-	time_t			nextcheck;
+	time64_t		nextcheck;
 	int			entries;
 
 	/* fields for communication over channel */
 	struct list_head	queue;
 
 	atomic_t		writers;		/* how many time is /channel open */
-	time_t			last_close;		/* if no writers, when did last close */
-	time_t			last_warn;		/* when we last warned about no writers */
+	time64_t		last_close;		/* if no writers, when did last close */
+	time64_t		last_warn;		/* when we last warned about no writers */
 
 	union {
 		struct proc_dir_entry	*procfs;
@@ -147,18 +147,22 @@ struct cache_deferred_req {
  * timestamps kept in the cache are expressed in seconds
  * since boot.  This is the best for measuring differences in
  * real time.
+ * This reimplemnts ktime_get_boottime_seconds() in a slightly
+ * faster but less accurate way. When we end up converting
+ * back to wallclock (CLOCK_REALTIME), that error often
+ * cancels out during the reverse operation.
  */
-static inline time_t seconds_since_boot(void)
+static inline time64_t seconds_since_boot(void)
 {
-	struct timespec boot;
-	getboottime(&boot);
-	return get_seconds() - boot.tv_sec;
+	struct timespec64 boot;
+	getboottime64(&boot);
+	return ktime_get_real_seconds() - boot.tv_sec;
 }
 
-static inline time_t convert_to_wallclock(time_t sinceboot)
+static inline time64_t convert_to_wallclock(time64_t sinceboot)
 {
-	struct timespec boot;
-	getboottime(&boot);
+	struct timespec64 boot;
+	getboottime64(&boot);
 	return boot.tv_sec + sinceboot;
 }
 
@@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint)
 	return 0;
 }
 
-static inline int get_time(char **bpp, time_t *time)
+static inline int get_time(char **bpp, time64_t *time)
 {
 	char buf[50];
 	long long ll;
@@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time)
 	if (kstrtoll(buf, 0, &ll))
 		return -EINVAL;
 
-	*time = (time_t)ll;
+	*time = ll;
 	return 0;
 }
 
-static inline time_t get_expiry(char **bpp)
+static inline time64_t get_expiry(char **bpp)
 {
-	time_t rv;
-	struct timespec boot;
+	time64_t rv;
+	struct timespec64 boot;
 
 	if (get_time(bpp, &rv))
 		return 0;
 	if (rv < 0)
 		return 0;
-	getboottime(&boot);
+	getboottime64(&boot);
 	return rv - boot.tv_sec;
 }
 
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 0c3e22838ddf..311181720d79 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd,
 	char *ep;
 	int len;
 	struct rsi rsii, *rsip = NULL;
-	time_t expiry;
+	time64_t expiry;
 	int status = -EINVAL;
 
 	memset(&rsii, 0, sizeof(rsii));
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index f740cb51802a..d996bf872a7c 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -42,7 +42,7 @@ static bool cache_listeners_exist(struct cache_detail *detail);
 
 static void cache_init(struct cache_head *h, struct cache_detail *detail)
 {
-	time_t now = seconds_since_boot();
+	time64_t now = seconds_since_boot();
 	INIT_HLIST_NODE(&h->cache_list);
 	h->flags = 0;
 	kref_init(&h->ref);
@@ -139,10 +139,10 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu);
 
 static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
 
-static void cache_fresh_locked(struct cache_head *head, time_t expiry,
+static void cache_fresh_locked(struct cache_head *head, time64_t expiry,
 			       struct cache_detail *detail)
 {
-	time_t now = seconds_since_boot();
+	time64_t now = seconds_since_boot();
 	if (now <= detail->flush_time)
 		/* ensure it isn't immediately treated as expired */
 		now = detail->flush_time + 1;
@@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail,
 		    struct cache_head *h, struct cache_req *rqstp)
 {
 	int rv;
-	long refresh_age, age;
+	time64_t refresh_age, age;
 
 	/* First decide return status as best we can */
 	rv = cache_is_valid(h);
@@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail,
 			rv = -ENOENT;
 	} else if (rv == -EAGAIN ||
 		   (h->expiry_time != 0 && age > refresh_age/2)) {
-		dprintk("RPC:       Want update, refage=%ld, age=%ld\n",
+		dprintk("RPC:       Want update, refage=%lld, age=%lld\n",
 				refresh_age, age);
 		if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
 			switch (cache_make_upcall(detail, h)) {
@@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p)
 		return cd->cache_show(m, cd, NULL);
 
 	ifdebug(CACHE)
-		seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
+		seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n",
 			   convert_to_wallclock(cp->expiry_time),
 			   kref_read(&cp->ref), cp->flags);
 	cache_get(cp);
@@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
 	char tbuf[22];
 	size_t len;
 
-	len = snprintf(tbuf, sizeof(tbuf), "%lu\n",
+	len = snprintf(tbuf, sizeof(tbuf), "%llu\n",
 			convert_to_wallclock(cd->flush_time));
 	return simple_read_from_buffer(buf, count, ppos, tbuf, len);
 }
@@ -1488,7 +1488,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
 {
 	char tbuf[20];
 	char *ep;
-	time_t now;
+	time64_t now;
 
 	if (*ppos || count > sizeof(tbuf)-1)
 		return -EINVAL;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 5c04ba7d456b..04aa80a2d752 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -166,7 +166,7 @@ static void ip_map_request(struct cache_detail *cd,
 }
 
 static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
-static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
 			  char *mesg, int mlen)
@@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd,
 
 	struct ip_map *ipmp;
 	struct auth_domain *dom;
-	time_t expiry;
+	time64_t expiry;
 
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
@@ -308,7 +308,7 @@ static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
 }
 
 static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
-		struct unix_domain *udom, time_t expiry)
+		struct unix_domain *udom, time64_t expiry)
 {
 	struct ip_map ip;
 	struct cache_head *ch;
@@ -328,7 +328,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
 }
 
 static inline int ip_map_update(struct net *net, struct ip_map *ipm,
-		struct unix_domain *udom, time_t expiry)
+		struct unix_domain *udom, time64_t expiry)
 {
 	struct sunrpc_net *sn;
 
@@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd,
 	int rv;
 	int i;
 	int err;
-	time_t expiry;
+	time64_t expiry;
 	struct unix_gid ug, *ugp;
 
 	if (mesg[mlen - 1] != '\n')
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 17/24] nfs: fix timstamp debug prints
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (15 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 16/24] nfs: use time64_t internally Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 18/24] nfs: fscache: use timespec64 in inode auxdata Arnd Bergmann
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Trond Myklebust, Anna Schumaker
  Cc: Arnd Bergmann, Chuck Lever, Donald Buczek, Olga Kornievskaia, linux-nfs

Starting in v5.5, the timestamps are correctly passed down as
64-bit seconds with NFSv4 on 32-bit machines, but some debug
statements still truncate them to 'long'.

Fixes: e86d5a02874c ("NFS: Convert struct nfs_fattr to use struct timespec64")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/nfs/nfs4xdr.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 936c57779ff4..728d88b6a698 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4097,7 +4097,7 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
 			status = NFS_ATTR_FATTR_ATIME;
 		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
 	}
-	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
+	dprintk("%s: atime=%lld\n", __func__, time->tv_sec);
 	return status;
 }
 
@@ -4115,7 +4115,7 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
 			status = NFS_ATTR_FATTR_CTIME;
 		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
 	}
-	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
+	dprintk("%s: ctime=%lld\n", __func__, time->tv_sec);
 	return status;
 }
 
@@ -4132,8 +4132,8 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
 		status = decode_attr_time(xdr, time);
 		bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
 	}
-	dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
-		(long)time->tv_nsec);
+	dprintk("%s: time_delta=%lld %ld\n", __func__, time->tv_sec,
+		time->tv_nsec);
 	return status;
 }
 
@@ -4197,7 +4197,7 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
 			status = NFS_ATTR_FATTR_MTIME;
 		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
 	}
-	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
+	dprintk("%s: mtime=%lld\n", __func__, time->tv_sec);
 	return status;
 }
 
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 18/24] nfs: fscache: use timespec64 in inode auxdata
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (16 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 17/24] nfs: fix timstamp debug prints Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t Arnd Bergmann
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Trond Myklebust, Anna Schumaker
  Cc: Arnd Bergmann, David Howells, Thomas Gleixner, linux-nfs

nfs currently behaves differently on 32-bit and 64-bit kernels regarding
the on-disk format of nfs_fscache_inode_auxdata.

That format should really be the same on any kernel, and we should avoid
the 'timespec' type in order to remove that from the kernel later on.

Using plain 'timespec64' would not be good here, since that includes
implied padding and would possibly leak kernel stack data to the on-disk
format on 32-bit architectures.

struct __kernel_timespec would work as a replacement, but open-coding
the two struct members in nfs_fscache_inode_auxdata makes it more
obvious what's going on here, and keeps the current format for 64-bit
architectures.

Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/nfs/fscache-index.c |  6 ++++--
 fs/nfs/fscache.c       | 18 ++++++++++++------
 fs/nfs/fscache.h       |  8 +++++---
 3 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c
index 15f271401dcc..573b1da9342c 100644
--- a/fs/nfs/fscache-index.c
+++ b/fs/nfs/fscache-index.c
@@ -84,8 +84,10 @@ enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data,
 		return FSCACHE_CHECKAUX_OBSOLETE;
 
 	memset(&auxdata, 0, sizeof(auxdata));
-	auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
-	auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
+	auxdata.mtime_sec  = nfsi->vfs_inode.i_mtime.tv_sec;
+	auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
+	auxdata.ctime_sec  = nfsi->vfs_inode.i_ctime.tv_sec;
+	auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
 
 	if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
 		auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 3800ab6f08fa..7def925d3af5 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -238,8 +238,10 @@ void nfs_fscache_init_inode(struct inode *inode)
 		return;
 
 	memset(&auxdata, 0, sizeof(auxdata));
-	auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
-	auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
+	auxdata.mtime_sec  = nfsi->vfs_inode.i_mtime.tv_sec;
+	auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
+	auxdata.ctime_sec  = nfsi->vfs_inode.i_ctime.tv_sec;
+	auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
 
 	if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
 		auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
@@ -263,8 +265,10 @@ void nfs_fscache_clear_inode(struct inode *inode)
 	dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
 
 	memset(&auxdata, 0, sizeof(auxdata));
-	auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
-	auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
+	auxdata.mtime_sec  = nfsi->vfs_inode.i_mtime.tv_sec;
+	auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
+	auxdata.ctime_sec  = nfsi->vfs_inode.i_ctime.tv_sec;
+	auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
 	fscache_relinquish_cookie(cookie, &auxdata, false);
 	nfsi->fscache = NULL;
 }
@@ -305,8 +309,10 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp)
 		return;
 
 	memset(&auxdata, 0, sizeof(auxdata));
-	auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
-	auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
+	auxdata.mtime_sec  = nfsi->vfs_inode.i_mtime.tv_sec;
+	auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
+	auxdata.ctime_sec  = nfsi->vfs_inode.i_ctime.tv_sec;
+	auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
 
 	if (inode_is_open_for_write(inode)) {
 		dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index ad041cfbf9ec..6754c8607230 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -62,9 +62,11 @@ struct nfs_fscache_key {
  * cache object.
  */
 struct nfs_fscache_inode_auxdata {
-	struct timespec	mtime;
-	struct timespec	ctime;
-	u64		change_attr;
+	s64	mtime_sec;
+	s64	mtime_nsec;
+	s64	ctime_sec;
+	s64	ctime_nsec;
+	u64	change_attr;
 };
 
 /*
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (17 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 18/24] nfs: fscache: use timespec64 in inode auxdata Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 21:18   ` Darrick J. Wong
  2019-12-13 20:53 ` [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time Arnd Bergmann
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Darrick J. Wong, linux-xfs
  Cc: Arnd Bergmann, Brian Foster, Eric Sandeen, Nick Bowler

The compat_time_t type has been removed everywhere else,
as most users rely on old_time32_t for both native and
compat mode handling of 32-bit time_t.

Remove the last one in xfs.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/xfs/xfs_ioctl32.c | 2 +-
 fs/xfs/xfs_ioctl32.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index c4c4f09113d3..a49bd80b2c3b 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -107,7 +107,7 @@ xfs_ioctl32_bstime_copyin(
 	xfs_bstime_t		*bstime,
 	compat_xfs_bstime_t	__user *bstime32)
 {
-	compat_time_t		sec32;	/* tv_sec differs on 64 vs. 32 */
+	old_time32_t		sec32;	/* tv_sec differs on 64 vs. 32 */
 
 	if (get_user(sec32,		&bstime32->tv_sec)	||
 	    get_user(bstime->tv_nsec,	&bstime32->tv_nsec))
diff --git a/fs/xfs/xfs_ioctl32.h b/fs/xfs/xfs_ioctl32.h
index 8c7743cd490e..053de7d894cd 100644
--- a/fs/xfs/xfs_ioctl32.h
+++ b/fs/xfs/xfs_ioctl32.h
@@ -32,7 +32,7 @@
 #endif
 
 typedef struct compat_xfs_bstime {
-	compat_time_t	tv_sec;		/* seconds		*/
+	old_time32_t	tv_sec;		/* seconds		*/
 	__s32		tv_nsec;	/* and nanoseconds	*/
 } compat_xfs_bstime_t;
 
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (18 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 21:05   ` Darrick J. Wong
  2019-12-13 20:53 ` [PATCH v2 21/24] xfs: quota: move to time64_t interfaces Arnd Bergmann
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Darrick J. Wong, linux-xfs
  Cc: Arnd Bergmann, Brian Foster, Dave Chinner, Allison Collins,
	Jan Kara, Eric Sandeen

When building a kernel that disables support for 32-bit time_t
system calls, it also makes sense to disable the old xfs_bstat
ioctls completely, as they truncate the timestamps to 32-bit
values.

Any application using these needs to be updated to use the v5
interfaces.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/xfs/xfs_ioctl.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 7b35d62ede9f..a4a4eed8879c 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -36,6 +36,7 @@
 #include "xfs_reflink.h"
 #include "xfs_ioctl.h"
 
+#include <linux/compat.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 
@@ -617,6 +618,23 @@ xfs_fsinumbers_fmt(
 	return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
 }
 
+/* disallow y2038-unsafe ioctls with CONFIG_COMPAT_32BIT_TIME=n */
+static bool xfs_have_compat_bstat_time32(unsigned int cmd)
+{
+	if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
+		return true;
+
+	if (IS_ENABLED(CONFIG_64BIT) && !in_compat_syscall())
+		return true;
+
+	if (cmd == XFS_IOC_FSBULKSTAT_SINGLE ||
+	    cmd == XFS_IOC_FSBULKSTAT ||
+	    cmd == XFS_IOC_SWAPEXT)
+		return false;
+
+	return true;
+}
+
 STATIC int
 xfs_ioc_fsbulkstat(
 	xfs_mount_t		*mp,
@@ -637,6 +655,9 @@ xfs_ioc_fsbulkstat(
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
+	if (!xfs_have_compat_bstat_time32(cmd))
+		return -EINVAL;
+
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
 
@@ -1815,6 +1836,11 @@ xfs_ioc_swapext(
 	struct fd	f, tmp;
 	int		error = 0;
 
+	if (xfs_have_compat_bstat_time32(XFS_IOC_SWAPEXT)) {
+		error = -EINVAL;
+		goto out;
+	}
+
 	/* Pull information for the target fd */
 	f = fdget((int)sxp->sx_fdtarget);
 	if (!f.file) {
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (19 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 21:17   ` Darrick J. Wong
  2019-12-13 20:53 ` [PATCH v2 22/24] y2038: remove obsolete jiffies conversion functions Arnd Bergmann
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Darrick J. Wong, linux-xfs
  Cc: Arnd Bergmann, Brian Foster, Carlos Maiolino, Pavel Reichl,
	Eric Sandeen, Dave Chinner, Allison Collins, Jan Kara

As a preparation for removing the 32-bit time_t type and
all associated interfaces, change xfs to use time64_t and
ktime_get_real_seconds() for the quota housekeeping.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/xfs/xfs_dquot.c       | 6 +++---
 fs/xfs/xfs_qm.h          | 6 +++---
 fs/xfs/xfs_quotaops.c    | 6 +++---
 fs/xfs/xfs_trans_dquot.c | 8 +++++---
 4 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 2bff21ca9d78..9cfd3209f52b 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -137,7 +137,7 @@ xfs_qm_adjust_dqtimers(
 		    (d->d_blk_hardlimit &&
 		     (be64_to_cpu(d->d_bcount) >
 		      be64_to_cpu(d->d_blk_hardlimit)))) {
-			d->d_btimer = cpu_to_be32(get_seconds() +
+			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
 					mp->m_quotainfo->qi_btimelimit);
 		} else {
 			d->d_bwarns = 0;
@@ -160,7 +160,7 @@ xfs_qm_adjust_dqtimers(
 		    (d->d_ino_hardlimit &&
 		     (be64_to_cpu(d->d_icount) >
 		      be64_to_cpu(d->d_ino_hardlimit)))) {
-			d->d_itimer = cpu_to_be32(get_seconds() +
+			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
 					mp->m_quotainfo->qi_itimelimit);
 		} else {
 			d->d_iwarns = 0;
@@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers(
 		    (d->d_rtb_hardlimit &&
 		     (be64_to_cpu(d->d_rtbcount) >
 		      be64_to_cpu(d->d_rtb_hardlimit)))) {
-			d->d_rtbtimer = cpu_to_be32(get_seconds() +
+			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
 					mp->m_quotainfo->qi_rtbtimelimit);
 		} else {
 			d->d_rtbwarns = 0;
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 7823af39008b..4e57edca8bce 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -64,9 +64,9 @@ struct xfs_quotainfo {
 	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
 	struct list_lru	 qi_lru;
 	int		 qi_dquots;
-	time_t		 qi_btimelimit;	 /* limit for blks timer */
-	time_t		 qi_itimelimit;	 /* limit for inodes timer */
-	time_t		 qi_rtbtimelimit;/* limit for rt blks timer */
+	time64_t	 qi_btimelimit;	 /* limit for blks timer */
+	time64_t	 qi_itimelimit;	 /* limit for inodes timer */
+	time64_t	 qi_rtbtimelimit;/* limit for rt blks timer */
 	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for blks warnings */
 	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for inodes warnings */
 	xfs_qwarncnt_t	 qi_rtbwarnlimit;/* limit for rt blks warnings */
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index c7de17deeae6..38669e827206 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -37,9 +37,9 @@ xfs_qm_fill_state(
 	tstate->flags |= QCI_SYSFILE;
 	tstate->blocks = ip->i_d.di_nblocks;
 	tstate->nextents = ip->i_d.di_nextents;
-	tstate->spc_timelimit = q->qi_btimelimit;
-	tstate->ino_timelimit = q->qi_itimelimit;
-	tstate->rt_spc_timelimit = q->qi_rtbtimelimit;
+	tstate->spc_timelimit = (u32)q->qi_btimelimit;
+	tstate->ino_timelimit = (u32)q->qi_itimelimit;
+	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
 	tstate->spc_warnlimit = q->qi_bwarnlimit;
 	tstate->ino_warnlimit = q->qi_iwarnlimit;
 	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index a6fe2d8dc40f..d1b9869bc5fa 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -580,7 +580,7 @@ xfs_trans_dqresv(
 {
 	xfs_qcnt_t		hardlimit;
 	xfs_qcnt_t		softlimit;
-	time_t			timer;
+	time64_t		timer;
 	xfs_qwarncnt_t		warns;
 	xfs_qwarncnt_t		warnlimit;
 	xfs_qcnt_t		total_count;
@@ -635,7 +635,8 @@ xfs_trans_dqresv(
 				goto error_return;
 			}
 			if (softlimit && total_count > softlimit) {
-				if ((timer != 0 && get_seconds() > timer) ||
+				if ((timer != 0 &&
+				     ktime_get_real_seconds() > timer) ||
 				    (warns != 0 && warns >= warnlimit)) {
 					xfs_quota_warn(mp, dqp,
 						       QUOTA_NL_BSOFTLONGWARN);
@@ -662,7 +663,8 @@ xfs_trans_dqresv(
 				goto error_return;
 			}
 			if (softlimit && total_count > softlimit) {
-				if  ((timer != 0 && get_seconds() > timer) ||
+				if  ((timer != 0 &&
+				      ktime_get_real_seconds() > timer) ||
 				     (warns != 0 && warns >= warnlimit)) {
 					xfs_quota_warn(mp, dqp,
 						       QUOTA_NL_ISOFTLONGWARN);
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 22/24] y2038: remove obsolete jiffies conversion functions
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (20 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 21/24] xfs: quota: move to time64_t interfaces Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 23/24] y2038: rename itimerval to __kernel_old_itimerval Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 24/24] y2038: sparc: remove use of struct timex Arnd Bergmann
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, John Stultz, Thomas Gleixner
  Cc: Arnd Bergmann, Stephen Boyd, Li RongQing, Zhang Yu,
	Pablo Neira Ayuso, Deepa Dinamani, Christian Brauner,
	Dmitry Safonov, zhengbin

Now that the last user of timespec_to_jiffies() is gone, these
can just be removed, everything else is using ktime_t or timespec64
already.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/linux/jiffies.h | 20 --------------
 kernel/time/time.c      | 58 ++++-------------------------------------
 2 files changed, 5 insertions(+), 73 deletions(-)

diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 1b6d31da7cbc..e3279ef24d28 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -422,26 +422,6 @@ static __always_inline unsigned long usecs_to_jiffies(const unsigned int u)
 extern unsigned long timespec64_to_jiffies(const struct timespec64 *value);
 extern void jiffies_to_timespec64(const unsigned long jiffies,
 				  struct timespec64 *value);
-static inline unsigned long timespec_to_jiffies(const struct timespec *value)
-{
-	struct timespec64 ts = timespec_to_timespec64(*value);
-
-	return timespec64_to_jiffies(&ts);
-}
-
-static inline void jiffies_to_timespec(const unsigned long jiffies,
-				       struct timespec *value)
-{
-	struct timespec64 ts;
-
-	jiffies_to_timespec64(jiffies, &ts);
-	*value = timespec64_to_timespec(ts);
-}
-
-extern unsigned long timeval_to_jiffies(const struct timeval *value);
-extern void jiffies_to_timeval(const unsigned long jiffies,
-			       struct timeval *value);
-
 extern clock_t jiffies_to_clock_t(unsigned long x);
 static inline clock_t jiffies_delta_to_clock_t(long delta)
 {
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 704ccd9451b0..cdd7386115ff 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -626,10 +626,12 @@ EXPORT_SYMBOL(__usecs_to_jiffies);
  * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec
  * value to a scaled second value.
  */
-static unsigned long
-__timespec64_to_jiffies(u64 sec, long nsec)
+
+unsigned long
+timespec64_to_jiffies(const struct timespec64 *value)
 {
-	nsec = nsec + TICK_NSEC - 1;
+	u64 sec = value->tv_sec;
+	long nsec = value->tv_nsec + TICK_NSEC - 1;
 
 	if (sec >= MAX_SEC_IN_JIFFIES){
 		sec = MAX_SEC_IN_JIFFIES;
@@ -640,18 +642,6 @@ __timespec64_to_jiffies(u64 sec, long nsec)
 		 (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
 
 }
-
-static unsigned long
-__timespec_to_jiffies(unsigned long sec, long nsec)
-{
-	return __timespec64_to_jiffies((u64)sec, nsec);
-}
-
-unsigned long
-timespec64_to_jiffies(const struct timespec64 *value)
-{
-	return __timespec64_to_jiffies(value->tv_sec, value->tv_nsec);
-}
 EXPORT_SYMBOL(timespec64_to_jiffies);
 
 void
@@ -668,44 +658,6 @@ jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value)
 }
 EXPORT_SYMBOL(jiffies_to_timespec64);
 
-/*
- * We could use a similar algorithm to timespec_to_jiffies (with a
- * different multiplier for usec instead of nsec). But this has a
- * problem with rounding: we can't exactly add TICK_NSEC - 1 to the
- * usec value, since it's not necessarily integral.
- *
- * We could instead round in the intermediate scaled representation
- * (i.e. in units of 1/2^(large scale) jiffies) but that's also
- * perilous: the scaling introduces a small positive error, which
- * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1
- * units to the intermediate before shifting) leads to accidental
- * overflow and overestimates.
- *
- * At the cost of one additional multiplication by a constant, just
- * use the timespec implementation.
- */
-unsigned long
-timeval_to_jiffies(const struct timeval *value)
-{
-	return __timespec_to_jiffies(value->tv_sec,
-				     value->tv_usec * NSEC_PER_USEC);
-}
-EXPORT_SYMBOL(timeval_to_jiffies);
-
-void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
-{
-	/*
-	 * Convert jiffies to nanoseconds and separate with
-	 * one divide.
-	 */
-	u32 rem;
-
-	value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
-				    NSEC_PER_SEC, &rem);
-	value->tv_usec = rem / NSEC_PER_USEC;
-}
-EXPORT_SYMBOL(jiffies_to_timeval);
-
 /*
  * Convert jiffies/jiffies_64 to clock_t and back.
  */
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 23/24] y2038: rename itimerval to __kernel_old_itimerval
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (21 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 22/24] y2038: remove obsolete jiffies conversion functions Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-13 20:53 ` [PATCH v2 24/24] y2038: sparc: remove use of struct timex Arnd Bergmann
  23 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, Thomas Gleixner
  Cc: Arnd Bergmann, David Howells, Al Viro, Christian Brauner,
	Heiko Carstens, Jens Axboe, Deepa Dinamani, David S. Miller,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	Anna-Maria Gleixner, linux-api

Take the renaming of timeval and timespec one level further,
also renaming itimerval to __kernel_old_itimerval, to avoid
namespace conflicts with the user-space structure that may
use 64-bit time_t members.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 include/linux/syscalls.h        |  9 ++++-----
 include/uapi/linux/time_types.h |  5 +++++
 kernel/time/itimer.c            | 18 +++++++++---------
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index d0391cc2dae9..27245fec2a8a 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -16,8 +16,7 @@ struct inode;
 struct iocb;
 struct io_event;
 struct iovec;
-struct itimerspec;
-struct itimerval;
+struct __kernel_old_itimerval;
 struct kexec_segment;
 struct linux_dirent;
 struct linux_dirent64;
@@ -591,10 +590,10 @@ asmlinkage long sys_nanosleep_time32(struct old_timespec32 __user *rqtp,
 				     struct old_timespec32 __user *rmtp);
 
 /* kernel/itimer.c */
-asmlinkage long sys_getitimer(int which, struct itimerval __user *value);
+asmlinkage long sys_getitimer(int which, struct __kernel_old_itimerval __user *value);
 asmlinkage long sys_setitimer(int which,
-				struct itimerval __user *value,
-				struct itimerval __user *ovalue);
+				struct __kernel_old_itimerval __user *value,
+				struct __kernel_old_itimerval __user *ovalue);
 
 /* kernel/kexec.c */
 asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
diff --git a/include/uapi/linux/time_types.h b/include/uapi/linux/time_types.h
index 074e391d73a1..bcc0002115d3 100644
--- a/include/uapi/linux/time_types.h
+++ b/include/uapi/linux/time_types.h
@@ -33,6 +33,11 @@ struct __kernel_old_timespec {
 	long			tv_nsec;	/* nanoseconds */
 };
 
+struct __kernel_old_itimerval {
+	struct __kernel_old_timeval it_interval;/* timer interval */
+	struct __kernel_old_timeval it_value;	/* current value */
+};
+
 struct __kernel_sock_timeval {
 	__s64 tv_sec;
 	__s64 tv_usec;
diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c
index 9e59c9ea92aa..ca4e6d57d68b 100644
--- a/kernel/time/itimer.c
+++ b/kernel/time/itimer.c
@@ -97,20 +97,20 @@ static int do_getitimer(int which, struct itimerspec64 *value)
 	return 0;
 }
 
-static int put_itimerval(struct itimerval __user *o,
+static int put_itimerval(struct __kernel_old_itimerval __user *o,
 			 const struct itimerspec64 *i)
 {
-	struct itimerval v;
+	struct __kernel_old_itimerval v;
 
 	v.it_interval.tv_sec = i->it_interval.tv_sec;
 	v.it_interval.tv_usec = i->it_interval.tv_nsec / NSEC_PER_USEC;
 	v.it_value.tv_sec = i->it_value.tv_sec;
 	v.it_value.tv_usec = i->it_value.tv_nsec / NSEC_PER_USEC;
-	return copy_to_user(o, &v, sizeof(struct itimerval)) ? -EFAULT : 0;
+	return copy_to_user(o, &v, sizeof(struct __kernel_old_itimerval)) ? -EFAULT : 0;
 }
 
 
-SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
+SYSCALL_DEFINE2(getitimer, int, which, struct __kernel_old_itimerval __user *, value)
 {
 	struct itimerspec64 get_buffer;
 	int error = do_getitimer(which, &get_buffer);
@@ -314,11 +314,11 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
 
 #endif
 
-static int get_itimerval(struct itimerspec64 *o, const struct itimerval __user *i)
+static int get_itimerval(struct itimerspec64 *o, const struct __kernel_old_itimerval __user *i)
 {
-	struct itimerval v;
+	struct __kernel_old_itimerval v;
 
-	if (copy_from_user(&v, i, sizeof(struct itimerval)))
+	if (copy_from_user(&v, i, sizeof(struct __kernel_old_itimerval)))
 		return -EFAULT;
 
 	/* Validate the timevals in value. */
@@ -333,8 +333,8 @@ static int get_itimerval(struct itimerspec64 *o, const struct itimerval __user *
 	return 0;
 }
 
-SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
-		struct itimerval __user *, ovalue)
+SYSCALL_DEFINE3(setitimer, int, which, struct __kernel_old_itimerval __user *, value,
+		struct __kernel_old_itimerval __user *, ovalue)
 {
 	struct itimerspec64 set_buffer, get_buffer;
 	int error;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v2 24/24] y2038: sparc: remove use of struct timex
  2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
                   ` (22 preceding siblings ...)
  2019-12-13 20:53 ` [PATCH v2 23/24] y2038: rename itimerval to __kernel_old_itimerval Arnd Bergmann
@ 2019-12-13 20:53 ` Arnd Bergmann
  2019-12-14  1:37   ` Julian Calaby
  23 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-13 20:53 UTC (permalink / raw)
  To: y2038, linux-kernel, David S. Miller, John Stultz, Thomas Gleixner
  Cc: Arnd Bergmann, Stephen Boyd, Deepa Dinamani, Eric W. Biederman,
	sparclinux

'struct timex' is one of the last users of 'struct timeval' and is
only referenced in one place in the kernel any more, to convert the
user space timex into the kernel-internal version on sparc64, with a
different tv_usec member type.

As a preparation for hiding the time_t definition and everything
using that in the kernel, change the implementation once more
to only convert the timeval member, and then enclose the
struct definition in an #ifdef.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/sparc/kernel/sys_sparc_64.c | 29 +++++++++++++++--------------
 include/uapi/linux/timex.h       |  2 ++
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
index 9f41a6f5a032..1c85b0af4dfd 100644
--- a/arch/sparc/kernel/sys_sparc_64.c
+++ b/arch/sparc/kernel/sys_sparc_64.c
@@ -548,34 +548,35 @@ SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len)
 	return err;
 }
 
-SYSCALL_DEFINE1(sparc_adjtimex, struct timex __user *, txc_p)
+SYSCALL_DEFINE1(sparc_adjtimex, struct __kernel_timex __user *, txc_p)
 {
-	struct timex txc;		/* Local copy of parameter */
-	struct __kernel_timex *kt = (void *)&txc;
+	struct __kernel_timex txc;
+	__kernel_old_timeval *tv = (void *)&txc->time;
 	int ret;
 
 	/* Copy the user data space into the kernel copy
 	 * structure. But bear in mind that the structures
 	 * may change
 	 */
-	if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
+	if (copy_from_user(&txc, txc_p, sizeof(txc)))
 		return -EFAULT;
 
 	/*
 	 * override for sparc64 specific timeval type: tv_usec
 	 * is 32 bit wide instead of 64-bit in __kernel_timex
 	 */
-	kt->time.tv_usec = txc.time.tv_usec;
+	kt->time.tv_usec = tv->tv_usec;
 	ret = do_adjtimex(kt);
-	txc.time.tv_usec = kt->time.tv_usec;
+	tv->tv_usec = kt->time.tv_usec;
 
-	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
+	return copy_to_user(txc_p, &txc, sizeof(txc)) ? -EFAULT : ret;
 }
 
-SYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock,struct timex __user *, txc_p)
+SYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock,
+		struct __kernel_timex __user *, txc_p)
 {
-	struct timex txc;		/* Local copy of parameter */
-	struct __kernel_timex *kt = (void *)&txc;
+	struct __kernel_timex txc;
+	__kernel_old_timeval *tv = (void *)&txc->time;
 	int ret;
 
 	if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) {
@@ -590,18 +591,18 @@ SYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock,struct timex _
 	 * structure. But bear in mind that the structures
 	 * may change
 	 */
-	if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
+	if (copy_from_user(&txc, txc_p, sizeof(txc)))
 		return -EFAULT;
 
 	/*
 	 * override for sparc64 specific timeval type: tv_usec
 	 * is 32 bit wide instead of 64-bit in __kernel_timex
 	 */
-	kt->time.tv_usec = txc.time.tv_usec;
+	kt->time.tv_usec = tv->tv_usec;
 	ret = do_clock_adjtime(which_clock, kt);
-	txc.time.tv_usec = kt->time.tv_usec;
+	tv->tv_usec = kt->time.tv_usec;
 
-	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
+	return copy_to_user(txc_p, &txc, sizeof(txc)) ? -EFAULT : ret;
 }
 
 SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type,
diff --git a/include/uapi/linux/timex.h b/include/uapi/linux/timex.h
index 9f517f9010bb..bd627c368d09 100644
--- a/include/uapi/linux/timex.h
+++ b/include/uapi/linux/timex.h
@@ -57,6 +57,7 @@
 
 #define NTP_API		4	/* NTP API version */
 
+#ifndef __KERNEL__
 /*
  * syscall interface - used (mainly by NTP daemon)
  * to discipline kernel clock oscillator
@@ -91,6 +92,7 @@ struct timex {
 	int  :32; int  :32; int  :32; int  :32;
 	int  :32; int  :32; int  :32;
 };
+#endif
 
 struct __kernel_timex_timeval {
 	__kernel_time64_t       tv_sec;
-- 
2.20.0


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time
  2019-12-13 20:53 ` [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time Arnd Bergmann
@ 2019-12-13 21:05   ` Darrick J. Wong
  2019-12-16 16:45     ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Darrick J. Wong @ 2019-12-13 21:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, linux-kernel, linux-xfs, Brian Foster, Dave Chinner,
	Allison Collins, Jan Kara, Eric Sandeen

On Fri, Dec 13, 2019 at 09:53:48PM +0100, Arnd Bergmann wrote:
> When building a kernel that disables support for 32-bit time_t
> system calls, it also makes sense to disable the old xfs_bstat
> ioctls completely, as they truncate the timestamps to 32-bit
> values.

Note that current xfs doesn't support > 32-bit timestamps at all, so for
now the old bulkstat/swapext ioctls will never overflow.

Granted, I melded everyone's suggestions into a more fully formed
'bigtime' feature patchset that I'll dump out soon as part of my usual
end of year carpetbombing of the mailing list, so we likely still need
most of this patch anyway...

> Any application using these needs to be updated to use the v5
> interfaces.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  fs/xfs/xfs_ioctl.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 7b35d62ede9f..a4a4eed8879c 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -36,6 +36,7 @@
>  #include "xfs_reflink.h"
>  #include "xfs_ioctl.h"
>  
> +#include <linux/compat.h>
>  #include <linux/mount.h>
>  #include <linux/namei.h>
>  
> @@ -617,6 +618,23 @@ xfs_fsinumbers_fmt(
>  	return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
>  }
>  
> +/* disallow y2038-unsafe ioctls with CONFIG_COMPAT_32BIT_TIME=n */
> +static bool xfs_have_compat_bstat_time32(unsigned int cmd)

The v5 bulkstat ioctls follow an entirely separate path through
xfs_ioctl.c, so I think you don't need the @cmd parameter.

> +{
> +	if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
> +		return true;
> +
> +	if (IS_ENABLED(CONFIG_64BIT) && !in_compat_syscall())
> +		return true;
> +
> +	if (cmd == XFS_IOC_FSBULKSTAT_SINGLE ||
> +	    cmd == XFS_IOC_FSBULKSTAT ||
> +	    cmd == XFS_IOC_SWAPEXT)
> +		return false;
> +
> +	return true;
> +}
> +
>  STATIC int
>  xfs_ioc_fsbulkstat(
>  	xfs_mount_t		*mp,
> @@ -637,6 +655,9 @@ xfs_ioc_fsbulkstat(
>  	if (!capable(CAP_SYS_ADMIN))
>  		return -EPERM;
>  
> +	if (!xfs_have_compat_bstat_time32(cmd))
> +		return -EINVAL;
> +
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
>  
> @@ -1815,6 +1836,11 @@ xfs_ioc_swapext(
>  	struct fd	f, tmp;
>  	int		error = 0;
>  
> +	if (xfs_have_compat_bstat_time32(XFS_IOC_SWAPEXT)) {

if (!xfs_have...()) ?

--D

> +		error = -EINVAL;
> +		goto out;
> +	}
> +
>  	/* Pull information for the target fd */
>  	f = fdget((int)sxp->sx_fdtarget);
>  	if (!f.file) {
> -- 
> 2.20.0
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-13 20:53 ` [PATCH v2 21/24] xfs: quota: move to time64_t interfaces Arnd Bergmann
@ 2019-12-13 21:17   ` Darrick J. Wong
  2019-12-16 16:52     ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Darrick J. Wong @ 2019-12-13 21:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, linux-kernel, linux-xfs, Brian Foster, Carlos Maiolino,
	Pavel Reichl, Eric Sandeen, Dave Chinner, Allison Collins,
	Jan Kara

On Fri, Dec 13, 2019 at 09:53:49PM +0100, Arnd Bergmann wrote:
> As a preparation for removing the 32-bit time_t type and
> all associated interfaces, change xfs to use time64_t and
> ktime_get_real_seconds() for the quota housekeeping.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Looks mostly reasonable to me...

The bigtime series refactors the triplicated timer handling and whatnot,
but I don't think it would be difficult to rebase that series assuming
this lands first (which it probably will, I expect a new incompat ondisk
feature to take a /long/ time to get through review.)

> ---
>  fs/xfs/xfs_dquot.c       | 6 +++---
>  fs/xfs/xfs_qm.h          | 6 +++---
>  fs/xfs/xfs_quotaops.c    | 6 +++---
>  fs/xfs/xfs_trans_dquot.c | 8 +++++---
>  4 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 2bff21ca9d78..9cfd3209f52b 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -137,7 +137,7 @@ xfs_qm_adjust_dqtimers(
>  		    (d->d_blk_hardlimit &&
>  		     (be64_to_cpu(d->d_bcount) >
>  		      be64_to_cpu(d->d_blk_hardlimit)))) {
> -			d->d_btimer = cpu_to_be32(get_seconds() +
> +			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
>  					mp->m_quotainfo->qi_btimelimit);
>  		} else {
>  			d->d_bwarns = 0;
> @@ -160,7 +160,7 @@ xfs_qm_adjust_dqtimers(
>  		    (d->d_ino_hardlimit &&
>  		     (be64_to_cpu(d->d_icount) >
>  		      be64_to_cpu(d->d_ino_hardlimit)))) {
> -			d->d_itimer = cpu_to_be32(get_seconds() +
> +			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
>  					mp->m_quotainfo->qi_itimelimit);
>  		} else {
>  			d->d_iwarns = 0;
> @@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers(
>  		    (d->d_rtb_hardlimit &&
>  		     (be64_to_cpu(d->d_rtbcount) >
>  		      be64_to_cpu(d->d_rtb_hardlimit)))) {
> -			d->d_rtbtimer = cpu_to_be32(get_seconds() +
> +			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
>  					mp->m_quotainfo->qi_rtbtimelimit);

Hmm, so one thing that I clean up on the way to bigtime is the total
lack of clamping here.  If (for example) it's September 2105 and
rtbtimelimit is set to 1 year, this will cause an integer overflow.  The
quota timer will be set to 1970 and expire immediately, rather than what
I'd consider the best effort of February 2106.

(I'll grant you the current code also behaves like this...)

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

>  		} else {
>  			d->d_rtbwarns = 0;
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 7823af39008b..4e57edca8bce 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -64,9 +64,9 @@ struct xfs_quotainfo {
>  	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
>  	struct list_lru	 qi_lru;
>  	int		 qi_dquots;
> -	time_t		 qi_btimelimit;	 /* limit for blks timer */
> -	time_t		 qi_itimelimit;	 /* limit for inodes timer */
> -	time_t		 qi_rtbtimelimit;/* limit for rt blks timer */
> +	time64_t	 qi_btimelimit;	 /* limit for blks timer */
> +	time64_t	 qi_itimelimit;	 /* limit for inodes timer */
> +	time64_t	 qi_rtbtimelimit;/* limit for rt blks timer */
>  	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for blks warnings */
>  	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for inodes warnings */
>  	xfs_qwarncnt_t	 qi_rtbwarnlimit;/* limit for rt blks warnings */
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index c7de17deeae6..38669e827206 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -37,9 +37,9 @@ xfs_qm_fill_state(
>  	tstate->flags |= QCI_SYSFILE;
>  	tstate->blocks = ip->i_d.di_nblocks;
>  	tstate->nextents = ip->i_d.di_nextents;
> -	tstate->spc_timelimit = q->qi_btimelimit;
> -	tstate->ino_timelimit = q->qi_itimelimit;
> -	tstate->rt_spc_timelimit = q->qi_rtbtimelimit;
> +	tstate->spc_timelimit = (u32)q->qi_btimelimit;
> +	tstate->ino_timelimit = (u32)q->qi_itimelimit;
> +	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
>  	tstate->spc_warnlimit = q->qi_bwarnlimit;
>  	tstate->ino_warnlimit = q->qi_iwarnlimit;
>  	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index a6fe2d8dc40f..d1b9869bc5fa 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -580,7 +580,7 @@ xfs_trans_dqresv(
>  {
>  	xfs_qcnt_t		hardlimit;
>  	xfs_qcnt_t		softlimit;
> -	time_t			timer;
> +	time64_t		timer;
>  	xfs_qwarncnt_t		warns;
>  	xfs_qwarncnt_t		warnlimit;
>  	xfs_qcnt_t		total_count;
> @@ -635,7 +635,8 @@ xfs_trans_dqresv(
>  				goto error_return;
>  			}
>  			if (softlimit && total_count > softlimit) {
> -				if ((timer != 0 && get_seconds() > timer) ||
> +				if ((timer != 0 &&
> +				     ktime_get_real_seconds() > timer) ||
>  				    (warns != 0 && warns >= warnlimit)) {
>  					xfs_quota_warn(mp, dqp,
>  						       QUOTA_NL_BSOFTLONGWARN);
> @@ -662,7 +663,8 @@ xfs_trans_dqresv(
>  				goto error_return;
>  			}
>  			if (softlimit && total_count > softlimit) {
> -				if  ((timer != 0 && get_seconds() > timer) ||
> +				if  ((timer != 0 &&
> +				      ktime_get_real_seconds() > timer) ||
>  				     (warns != 0 && warns >= warnlimit)) {
>  					xfs_quota_warn(mp, dqp,
>  						       QUOTA_NL_ISOFTLONGWARN);
> -- 
> 2.20.0
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t
  2019-12-13 20:53 ` [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t Arnd Bergmann
@ 2019-12-13 21:18   ` Darrick J. Wong
  2019-12-16 16:31     ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Darrick J. Wong @ 2019-12-13 21:18 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, linux-kernel, linux-xfs, Brian Foster, Eric Sandeen, Nick Bowler

On Fri, Dec 13, 2019 at 09:53:47PM +0100, Arnd Bergmann wrote:
> The compat_time_t type has been removed everywhere else,
> as most users rely on old_time32_t for both native and
> compat mode handling of 32-bit time_t.
> 
> Remove the last one in xfs.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Looks fine to me, assuming that compat_time_t -> old_time32_t.
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/xfs_ioctl32.c | 2 +-
>  fs/xfs/xfs_ioctl32.h | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> index c4c4f09113d3..a49bd80b2c3b 100644
> --- a/fs/xfs/xfs_ioctl32.c
> +++ b/fs/xfs/xfs_ioctl32.c
> @@ -107,7 +107,7 @@ xfs_ioctl32_bstime_copyin(
>  	xfs_bstime_t		*bstime,
>  	compat_xfs_bstime_t	__user *bstime32)
>  {
> -	compat_time_t		sec32;	/* tv_sec differs on 64 vs. 32 */
> +	old_time32_t		sec32;	/* tv_sec differs on 64 vs. 32 */
>  
>  	if (get_user(sec32,		&bstime32->tv_sec)	||
>  	    get_user(bstime->tv_nsec,	&bstime32->tv_nsec))
> diff --git a/fs/xfs/xfs_ioctl32.h b/fs/xfs/xfs_ioctl32.h
> index 8c7743cd490e..053de7d894cd 100644
> --- a/fs/xfs/xfs_ioctl32.h
> +++ b/fs/xfs/xfs_ioctl32.h
> @@ -32,7 +32,7 @@
>  #endif
>  
>  typedef struct compat_xfs_bstime {
> -	compat_time_t	tv_sec;		/* seconds		*/
> +	old_time32_t	tv_sec;		/* seconds		*/
>  	__s32		tv_nsec;	/* and nanoseconds	*/
>  } compat_xfs_bstime_t;
>  
> -- 
> 2.20.0
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64
  2019-12-13 20:49 ` [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64 Arnd Bergmann
@ 2019-12-13 22:08   ` Dmitry Torokhov
  0 siblings, 0 replies; 46+ messages in thread
From: Dmitry Torokhov @ 2019-12-13 22:08 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, linux-kernel, Deepa Dinamani, sparclinux, David S. Miller,
	stable, Bjorn Helgaas, Lubomir Rintel, Thomas Gleixner,
	linux-input

On Fri, Dec 13, 2019 at 09:49:10PM +0100, Arnd Bergmann wrote:
> Going through all uses of timeval, I noticed that we screwed up
> input_event in the previous attempts to fix it:
> 
> The time fields now match between kernel and user space, but
> all following fields are in the wrong place.
> 
> Add the required padding that is implied by the glibc timeval
> definition to fix the layout, and use a struct initializer
> to avoid leaking kernel stack data.
> 
> Cc: sparclinux@vger.kernel.org
> Cc: "David S. Miller" <davem@davemloft.net>
> Fixes: 141e5dcaa735 ("Input: input_event - fix the CONFIG_SPARC64 mixup")
> Fixes: 2e746942ebac ("Input: input_event - provide override for sparc64")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Applied, thank you.

> ---
>  drivers/input/evdev.c       | 14 +++++++-------
>  drivers/input/misc/uinput.c | 14 +++++++++-----
>  include/uapi/linux/input.h  |  1 +
>  3 files changed, 17 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
> index d7dd6fcf2db0..f918fca9ada3 100644
> --- a/drivers/input/evdev.c
> +++ b/drivers/input/evdev.c
> @@ -224,13 +224,13 @@ static void __pass_event(struct evdev_client *client,
>  		 */
>  		client->tail = (client->head - 2) & (client->bufsize - 1);
>  
> -		client->buffer[client->tail].input_event_sec =
> -						event->input_event_sec;
> -		client->buffer[client->tail].input_event_usec =
> -						event->input_event_usec;
> -		client->buffer[client->tail].type = EV_SYN;
> -		client->buffer[client->tail].code = SYN_DROPPED;
> -		client->buffer[client->tail].value = 0;
> +		client->buffer[client->tail] = (struct input_event) {
> +			.input_event_sec = event->input_event_sec,
> +			.input_event_usec = event->input_event_usec,
> +			.type = EV_SYN,
> +			.code = SYN_DROPPED,
> +			.value = 0,
> +		};
>  
>  		client->packet_head = client->tail;
>  	}
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index fd253781be71..2dabbe47d43e 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -74,12 +74,16 @@ static int uinput_dev_event(struct input_dev *dev,
>  	struct uinput_device	*udev = input_get_drvdata(dev);
>  	struct timespec64	ts;
>  
> -	udev->buff[udev->head].type = type;
> -	udev->buff[udev->head].code = code;
> -	udev->buff[udev->head].value = value;
>  	ktime_get_ts64(&ts);
> -	udev->buff[udev->head].input_event_sec = ts.tv_sec;
> -	udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
> +
> +	udev->buff[udev->head] = (struct input_event) {
> +		.input_event_sec = ts.tv_sec,
> +		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,
> +		.type = type,
> +		.code = code,
> +		.value = value,
> +	};
> +
>  	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
>  
>  	wake_up_interruptible(&udev->waitq);
> diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
> index f056b2a00d5c..9a61c28ed3ae 100644
> --- a/include/uapi/linux/input.h
> +++ b/include/uapi/linux/input.h
> @@ -34,6 +34,7 @@ struct input_event {
>  	__kernel_ulong_t __sec;
>  #if defined(__sparc__) && defined(__arch64__)
>  	unsigned int __usec;
> +	unsigned int __pad;
>  #else
>  	__kernel_ulong_t __usec;
>  #endif
> -- 
> 2.20.0
> 

-- 
Dmitry

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 24/24] y2038: sparc: remove use of struct timex
  2019-12-13 20:53 ` [PATCH v2 24/24] y2038: sparc: remove use of struct timex Arnd Bergmann
@ 2019-12-14  1:37   ` Julian Calaby
  2019-12-14 14:44     ` [Y2038] " Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Julian Calaby @ 2019-12-14  1:37 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, LKML, David S. Miller, John Stultz, Thomas Gleixner,
	Stephen Boyd, Deepa Dinamani, Eric W. Biederman, sparclinux

Hi Arnd,

On Sat, Dec 14, 2019 at 7:59 AM Arnd Bergmann <arnd@arndb.de> wrote:
>
> 'struct timex' is one of the last users of 'struct timeval' and is
> only referenced in one place in the kernel any more, to convert the
> user space timex into the kernel-internal version on sparc64, with a
> different tv_usec member type.
>
> As a preparation for hiding the time_t definition and everything
> using that in the kernel, change the implementation once more
> to only convert the timeval member, and then enclose the
> struct definition in an #ifdef.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  arch/sparc/kernel/sys_sparc_64.c | 29 +++++++++++++++--------------
>  include/uapi/linux/timex.h       |  2 ++
>  2 files changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
> index 9f41a6f5a032..1c85b0af4dfd 100644
> --- a/arch/sparc/kernel/sys_sparc_64.c
> +++ b/arch/sparc/kernel/sys_sparc_64.c
> @@ -548,34 +548,35 @@ SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len)
>         return err;
>  }
>
> -SYSCALL_DEFINE1(sparc_adjtimex, struct timex __user *, txc_p)
> +SYSCALL_DEFINE1(sparc_adjtimex, struct __kernel_timex __user *, txc_p)
>  {
> -       struct timex txc;               /* Local copy of parameter */
> -       struct __kernel_timex *kt = (void *)&txc;
> +       struct __kernel_timex txc;
> +       __kernel_old_timeval *tv = (void *)&txc->time;
>         int ret;
>
>         /* Copy the user data space into the kernel copy
>          * structure. But bear in mind that the structures
>          * may change
>          */
> -       if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
> +       if (copy_from_user(&txc, txc_p, sizeof(txc)))
>                 return -EFAULT;
>
>         /*
>          * override for sparc64 specific timeval type: tv_usec
>          * is 32 bit wide instead of 64-bit in __kernel_timex
>          */
> -       kt->time.tv_usec = txc.time.tv_usec;
> +       kt->time.tv_usec = tv->tv_usec;

Am I mis-reading the patch, or is "kt" not defined?

Thanks,

-- 
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Y2038] [PATCH v2 24/24] y2038: sparc: remove use of struct timex
  2019-12-14  1:37   ` Julian Calaby
@ 2019-12-14 14:44     ` Arnd Bergmann
  0 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-14 14:44 UTC (permalink / raw)
  To: Julian Calaby
  Cc: y2038 Mailman List, LKML, Stephen Boyd, John Stultz,
	Deepa Dinamani, sparclinux, Thomas Gleixner, David S. Miller,
	Eric W. Biederman

On Sat, Dec 14, 2019 at 2:38 AM Julian Calaby <julian.calaby@gmail.com> wrote:
> On Sat, Dec 14, 2019 at 7:59 AM Arnd Bergmann <arnd@arndb.de> wrote:
>
> Am I mis-reading the patch, or is "kt" not defined?

You are right, and there are other problems in this patch that I should have
found in a trivial compile-test. Please disregard this patch, it should not have
been part of this set before I had gotten around to at least some testing.

When I collected stuff from my backlog, I only made sure that this one had
no dependencies on other work, but failed to realize that sparc64 was not
part of my build test matrix and that the 0day bot had not seen it either.

       Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition
  2019-12-13 20:52 ` [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition Arnd Bergmann
@ 2019-12-16 13:14   ` Jan Kara
  0 siblings, 0 replies; 46+ messages in thread
From: Jan Kara @ 2019-12-16 13:14 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: y2038, linux-kernel, Jan Kara

On Fri 13-12-19 21:52:14, Arnd Bergmann wrote:
> The time_t type is part of the user interface and not always the
> same, with the move to 64-bit timestamps and the difference between
> architectures.
> 
> Make the quota format definition independent of this type and use
> a basic type of the same length. Make it unsigned in the process
> to keep the v1 format working until year 2106 instead of 2038
> on 32-bit architectures.
> 
> Hopefully, everybody has already moved to a newer format long
> ago (v2 was introduced with linux-2.4), but it's hard to be sure.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

What's worse, time_t is actually a part of on-disk format for this ancient
quota format making format incompatible between 32-bit and 64-bit
systems... Anyway, your patch looks good, I'll add it to my tree (speak up
if you want to merge it yourself due to something depending on it).

								Honza

> ---
>  fs/quota/quotaio_v1.h | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/quota/quotaio_v1.h b/fs/quota/quotaio_v1.h
> index bd11e2c08119..31dca9a89176 100644
> --- a/fs/quota/quotaio_v1.h
> +++ b/fs/quota/quotaio_v1.h
> @@ -25,8 +25,10 @@ struct v1_disk_dqblk {
>  	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
>  	__u32 dqb_isoftlimit;	/* preferred inode limit */
>  	__u32 dqb_curinodes;	/* current # allocated inodes */
> -	time_t dqb_btime;	/* time limit for excessive disk use */
> -	time_t dqb_itime;	/* time limit for excessive inode use */
> +
> +	/* below fields differ in length on 32-bit vs 64-bit architectures */
> +	unsigned long dqb_btime; /* time limit for excessive disk use */
> +	unsigned long dqb_itime; /* time limit for excessive inode use */
>  };
>  
>  #define v1_dqoff(UID)      ((loff_t)((UID) * sizeof (struct v1_disk_dqblk)))
> -- 
> 2.20.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t
  2019-12-13 21:18   ` Darrick J. Wong
@ 2019-12-16 16:31     ` Arnd Bergmann
  0 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-16 16:31 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Eric Sandeen, Nick Bowler

On Fri, Dec 13, 2019 at 10:18 PM Darrick J. Wong
<darrick.wong@oracle.com> wrote:
>
> On Fri, Dec 13, 2019 at 09:53:47PM +0100, Arnd Bergmann wrote:
> > The compat_time_t type has been removed everywhere else,
> > as most users rely on old_time32_t for both native and
> > compat mode handling of 32-bit time_t.
> >
> > Remove the last one in xfs.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>
> Looks fine to me, assuming that compat_time_t -> old_time32_t.

Yes, that's the idea. Christoph asked for the global change last year
as a cleanup,
but I left out xfs and a few others at the time when I was missing
other patches.

> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

Thanks,

     Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time
  2019-12-13 21:05   ` Darrick J. Wong
@ 2019-12-16 16:45     ` Arnd Bergmann
  2019-12-16 16:52       ` Darrick J. Wong
  0 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-16 16:45 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Dave Chinner, Allison Collins, Jan Kara, Eric Sandeen

On Fri, Dec 13, 2019 at 10:05 PM Darrick J. Wong
<darrick.wong@oracle.com> wrote:
>
> On Fri, Dec 13, 2019 at 09:53:48PM +0100, Arnd Bergmann wrote:
> > When building a kernel that disables support for 32-bit time_t
> > system calls, it also makes sense to disable the old xfs_bstat
> > ioctls completely, as they truncate the timestamps to 32-bit
> > values.
>
> Note that current xfs doesn't support > 32-bit timestamps at all, so for
> now the old bulkstat/swapext ioctls will never overflow.

Right, this patch originally came after my version of the 40-bit
timestamps that I dropped from the series now.

I've added "... once the extended times are supported." above now.

> Granted, I melded everyone's suggestions into a more fully formed
> 'bigtime' feature patchset that I'll dump out soon as part of my usual
> end of year carpetbombing of the mailing list, so we likely still need
> most of this patch anyway...

What is the timeline for that work now? I'm mainly interested in
getting the removal of 'time_t/timeval/timespec' and 'get_seconds()'
from the kernel done for v5.6, but it would be good to also have
this patch and the extended timestamps in the same version
just so we can claim that "all known y2038 issues" are addressed
in that release (I'm sure we will run into bugs we don't know yet).

> > @@ -617,6 +618,23 @@ xfs_fsinumbers_fmt(
> >       return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
> >  }
> >
> > +/* disallow y2038-unsafe ioctls with CONFIG_COMPAT_32BIT_TIME=n */
> > +static bool xfs_have_compat_bstat_time32(unsigned int cmd)
>
> The v5 bulkstat ioctls follow an entirely separate path through
> xfs_ioctl.c, so I think you don't need the @cmd parameter.

The check is there to not forbid XFS_IOC_FSINUMBERS at
the moment, since that is not affected.

> > @@ -1815,6 +1836,11 @@ xfs_ioc_swapext(
> >       struct fd       f, tmp;
> >       int             error = 0;
> >
> > +     if (xfs_have_compat_bstat_time32(XFS_IOC_SWAPEXT)) {
>
> if (!xfs_have...()) ?

Right, fixed now.

       Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time
  2019-12-16 16:45     ` Arnd Bergmann
@ 2019-12-16 16:52       ` Darrick J. Wong
  2019-12-17 15:06         ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Darrick J. Wong @ 2019-12-16 16:52 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Dave Chinner, Allison Collins, Jan Kara, Eric Sandeen

On Mon, Dec 16, 2019 at 05:45:29PM +0100, Arnd Bergmann wrote:
> On Fri, Dec 13, 2019 at 10:05 PM Darrick J. Wong
> <darrick.wong@oracle.com> wrote:
> >
> > On Fri, Dec 13, 2019 at 09:53:48PM +0100, Arnd Bergmann wrote:
> > > When building a kernel that disables support for 32-bit time_t
> > > system calls, it also makes sense to disable the old xfs_bstat
> > > ioctls completely, as they truncate the timestamps to 32-bit
> > > values.
> >
> > Note that current xfs doesn't support > 32-bit timestamps at all, so for
> > now the old bulkstat/swapext ioctls will never overflow.
> 
> Right, this patch originally came after my version of the 40-bit
> timestamps that I dropped from the series now.
> 
> I've added "... once the extended times are supported." above now.
> 
> > Granted, I melded everyone's suggestions into a more fully formed
> > 'bigtime' feature patchset that I'll dump out soon as part of my usual
> > end of year carpetbombing of the mailing list, so we likely still need
> > most of this patch anyway...
> 
> What is the timeline for that work now? I'm mainly interested in
> getting the removal of 'time_t/timeval/timespec' and 'get_seconds()'
> from the kernel done for v5.6, but it would be good to also have
> this patch and the extended timestamps in the same version
> just so we can claim that "all known y2038 issues" are addressed
> in that release (I'm sure we will run into bugs we don't know yet).

Personally, I think you should push this whenever it's ready.  Are you
aiming to send all 24 patches as a treewide pull request directly to
Linus, or would you rather the 2-3 xfs patches go through the xfs tree?

The y2038 format changes are going to take a while to push through
review.  If somehow it all gets through review for 5.6 I can always
apply both and fix the merge damage, but more likely y2038 timestamps is
a <cough> 5.8 EXPERIMENTAL thing.

Or later, given that Dave and I both have years worth of unreviewed
patch backlog. :(

> > > @@ -617,6 +618,23 @@ xfs_fsinumbers_fmt(
> > >       return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
> > >  }
> > >
> > > +/* disallow y2038-unsafe ioctls with CONFIG_COMPAT_32BIT_TIME=n */
> > > +static bool xfs_have_compat_bstat_time32(unsigned int cmd)
> >
> > The v5 bulkstat ioctls follow an entirely separate path through
> > xfs_ioctl.c, so I think you don't need the @cmd parameter.
> 
> The check is there to not forbid XFS_IOC_FSINUMBERS at
> the moment, since that is not affected.

Aha.

> > > @@ -1815,6 +1836,11 @@ xfs_ioc_swapext(
> > >       struct fd       f, tmp;
> > >       int             error = 0;
> > >
> > > +     if (xfs_have_compat_bstat_time32(XFS_IOC_SWAPEXT)) {
> >
> > if (!xfs_have...()) ?
> 
> Right, fixed now.

<nod>

--D

>        Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-13 21:17   ` Darrick J. Wong
@ 2019-12-16 16:52     ` Arnd Bergmann
  2019-12-17 15:02       ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-16 16:52 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Carlos Maiolino, Pavel Reichl, Eric Sandeen, Dave Chinner,
	Allison Collins, Jan Kara

On Fri, Dec 13, 2019 at 10:17 PM Darrick J. Wong
<darrick.wong@oracle.com> wrote:
>
> On Fri, Dec 13, 2019 at 09:53:49PM +0100, Arnd Bergmann wrote:
> > As a preparation for removing the 32-bit time_t type and
> > all associated interfaces, change xfs to use time64_t and
> > ktime_get_real_seconds() for the quota housekeeping.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>
> Looks mostly reasonable to me...
>
> The bigtime series refactors the triplicated timer handling and whatnot,
> but I don't think it would be difficult to rebase that series assuming
> this lands first (which it probably will, I expect a new incompat ondisk
> feature to take a /long/ time to get through review.)

Could you just merge my three patches into your tree then once
you are happy with all the changes?

> > @@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers(
> >                   (d->d_rtb_hardlimit &&
> >                    (be64_to_cpu(d->d_rtbcount) >
> >                     be64_to_cpu(d->d_rtb_hardlimit)))) {
> > -                     d->d_rtbtimer = cpu_to_be32(get_seconds() +
> > +                     d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
> >                                       mp->m_quotainfo->qi_rtbtimelimit);
>
> Hmm, so one thing that I clean up on the way to bigtime is the total
> lack of clamping here.  If (for example) it's September 2105 and
> rtbtimelimit is set to 1 year, this will cause an integer overflow.  The
> quota timer will be set to 1970 and expire immediately, rather than what
> I'd consider the best effort of February 2106.

I don't think clamping would be good here, that just replaces
one bug with another at the overflow time. If you would like to
have something better before this gets extended, I could try to
come up with a version that converts it to the nearest 64-bit
timestamp, similar to the way that time_before32() in the kernel
or the NTP protocol work.

If you think it can get extended properly soon, I'd just leave the
patch as it is today in order to remove the get_seconds()
interface for v5.6.

> (I'll grant you the current code also behaves like this...)
>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

Thanks,

       Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-16 16:52     ` Arnd Bergmann
@ 2019-12-17 15:02       ` Arnd Bergmann
  2019-12-17 22:15         ` Darrick J. Wong
  0 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-17 15:02 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Carlos Maiolino, Pavel Reichl, Eric Sandeen, Dave Chinner,
	Allison Collins, Jan Kara

On Mon, Dec 16, 2019 at 5:52 PM Arnd Bergmann <arnd@arndb.de> wrote:
> On Fri, Dec 13, 2019 at 10:17 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
>>
>> Hmm, so one thing that I clean up on the way to bigtime is the total
>> lack of clamping here.  If (for example) it's September 2105 and
>> rtbtimelimit is set to 1 year, this will cause an integer overflow.  The
>> quota timer will be set to 1970 and expire immediately, rather than what
>> I'd consider the best effort of February 2106.

One more hing to note (I will add this to the changelog text) is that on
32-bit architectures, the limit here is y2038, while on 64-bit
architectures it's y2106:

int xfs_trans_dqresv(...)
{
       time_t                  timer; /* signed 'long' */
       timer = be32_to_cpu(dqp->q_core.d_btimer);
       /* get_seconds() returns unsigned long */
      if ((timer != 0 && get_seconds() > timer))
                return -EDQUOT;
}

> I don't think clamping would be good here, that just replaces
> one bug with another at the overflow time. If you would like to
> have something better before this gets extended, I could try to
> come up with a version that converts it to the nearest 64-bit
> timestamp, similar to the way that time_before32() in the kernel
> or the NTP protocol work.
>
> If you think it can get extended properly soon, I'd just leave the
> patch as it is today in order to remove the get_seconds()
> interface for v5.6.

I've tried this now, and but this feels wrong: it adds lots of complexity
for corner cases and is still fragile, e.g. when the time is wrong
during boot before ntp runs. See that patch below for reference.

I also see that quotatool on xfs always uses the old xfs quota
interface, so it already overflows on the user space side. Fixing
this properly seems to be a bigger effort than I was planning for
(on an unpatched 64-bit kernel):

$ sudo quotatool -b    -u  -t 220month  /mnt/tmp -r
$ rm file ; fallocate -l 11M file
$ sudo quotatool -d /mnt/tmp -u arnd
1000 /mnt/tmp 11264 10240 20480 570239975 2 0 00
$ sudo quotatool -b    -u  -t 222month  /mnt/tmp -r
$ rm file ; fallocate -l 11M file
$ sudo quotatool -d /mnt/tmp -u arnd
1000 /mnt/tmp 11264 10240 20480 18446744069990008316 2 0 00

       Arnd

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 9cfd3209f52b..6c9128bb607b 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -98,6 +98,23 @@ xfs_qm_adjust_dqlimits(
                xfs_dquot_set_prealloc_limits(dq);
 }

+static __be32 xfs_quota_timeout32(s64 limit)
+{
+       time64_t now = ktime_get_real_seconds();
+       u32 timeout;
+
+       /* avoid overflows in out-of-range limits */
+       if ((u64)limit > S32_MAX)
+               limit = S32_MAX;
+       timeout = now + limit;
+
+       /* avoid timeout of zero */
+       if (lower_32_bits(timeout) == 0)
+               return cpu_to_be32(1);
+
+       return cpu_to_be32(lower_32_bits(timeout));
+}
+
 /*
  * Check the limits and timers of a dquot and start or reset timers
  * if necessary.
@@ -137,7 +154,7 @@ xfs_qm_adjust_dqtimers(
                    (d->d_blk_hardlimit &&
                     (be64_to_cpu(d->d_bcount) >
                      be64_to_cpu(d->d_blk_hardlimit)))) {
-                       d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
+                       d->d_btimer = xfs_quota_timeout32(
                                        mp->m_quotainfo->qi_btimelimit);
                } else {
                        d->d_bwarns = 0;
@@ -160,7 +177,7 @@ xfs_qm_adjust_dqtimers(
                    (d->d_ino_hardlimit &&
                     (be64_to_cpu(d->d_icount) >
                      be64_to_cpu(d->d_ino_hardlimit)))) {
-                       d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
+                       d->d_itimer = xfs_quota_timeout32(
                                        mp->m_quotainfo->qi_itimelimit);
                } else {
                        d->d_iwarns = 0;
@@ -183,7 +200,7 @@ xfs_qm_adjust_dqtimers(
                    (d->d_rtb_hardlimit &&
                     (be64_to_cpu(d->d_rtbcount) >
                      be64_to_cpu(d->d_rtb_hardlimit)))) {
-                       d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
+                       d->d_rtbtimer = xfs_quota_timeout32(
                                        mp->m_quotainfo->qi_rtbtimelimit);
                } else {
                        d->d_rtbwarns = 0;
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 1ea82764bf89..2087626b4bee 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -601,6 +601,14 @@ xfs_qm_scall_setqlim(
        return error;
 }

+/* Assume timers are within +/- 68 years of current wall clock */
+static time64_t xfs_quota_time32_to_time64(time64_t now, __be32 timer)
+{
+       s32 diff = be32_to_cpu(timer) - lower_32_bits(now);
+
+       return now + diff;
+}
+
 /* Fill out the quota context. */
 static void
 xfs_qm_scall_getquota_fill_qc(
@@ -609,6 +617,8 @@ xfs_qm_scall_getquota_fill_qc(
        const struct xfs_dquot  *dqp,
        struct qc_dqblk         *dst)
 {
+       time64_t now = ktime_get_real_seconds();
+
        memset(dst, 0, sizeof(*dst));
        dst->d_spc_hardlimit =
                XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
@@ -618,8 +628,8 @@ xfs_qm_scall_getquota_fill_qc(
        dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
        dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount);
        dst->d_ino_count = dqp->q_res_icount;
-       dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer);
-       dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer);
+       dst->d_spc_timer = xfs_quota_time32_to_time64(now,
dqp->q_core.d_btimer);
+       dst->d_ino_timer = xfs_quota_time32_to_time64(now,
dqp->q_core.d_itimer);
        dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns);
        dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns);
        dst->d_rt_spc_hardlimit =
@@ -627,7 +637,7 @@ xfs_qm_scall_getquota_fill_qc(
        dst->d_rt_spc_softlimit =
                XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
        dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount);
-       dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+       dst->d_rt_spc_timer = xfs_quota_time32_to_time64(now,
dqp->q_core.d_rtbtimer);
        dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);

        /*
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index d1b9869bc5fa..c75887da6546 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -636,7 +636,8 @@ xfs_trans_dqresv(
                        }
                        if (softlimit && total_count > softlimit) {
                                if ((timer != 0 &&
-                                    ktime_get_real_seconds() > timer) ||
+                                    time_after32(ktime_get_real_seconds(),
+                                                 timer)) ||
                                    (warns != 0 && warns >= warnlimit)) {
                                        xfs_quota_warn(mp, dqp,
                                                       QUOTA_NL_BSOFTLONGWARN);
@@ -664,7 +665,8 @@ xfs_trans_dqresv(
                        }
                        if (softlimit && total_count > softlimit) {
                                if  ((timer != 0 &&
-                                     ktime_get_real_seconds() > timer) ||
+                                    time_after32(ktime_get_real_seconds(),
+                                                 timer)) ||
                                     (warns != 0 && warns >= warnlimit)) {
                                        xfs_quota_warn(mp, dqp,
                                                       QUOTA_NL_ISOFTLONGWARN);

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time
  2019-12-16 16:52       ` Darrick J. Wong
@ 2019-12-17 15:06         ` Arnd Bergmann
  0 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-17 15:06 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Dave Chinner, Allison Collins, Jan Kara, Eric Sandeen

On Mon, Dec 16, 2019 at 5:52 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
> On Mon, Dec 16, 2019 at 05:45:29PM +0100, Arnd Bergmann wrote:
> > On Fri, Dec 13, 2019 at 10:05 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
> > What is the timeline for that work now? I'm mainly interested in
> > getting the removal of 'time_t/timeval/timespec' and 'get_seconds()'
> > from the kernel done for v5.6, but it would be good to also have
> > this patch and the extended timestamps in the same version
> > just so we can claim that "all known y2038 issues" are addressed
> > in that release (I'm sure we will run into bugs we don't know yet).
>
> Personally, I think you should push this whenever it's ready.  Are you
> aiming to send all 24 patches as a treewide pull request directly to
> Linus, or would you rather the 2-3 xfs patches go through the xfs tree?

My plan is get as much of the remaining 60 patches into maintainer
trees for v5.6 and then send a pull request for whatever remains that
has not been picked up by anyone.

The 24 patches are the ones that didn't seem worth splitting into a
separate series, aside from these I also have v4l2, alsa and nfsd
pending, plus a final cleanup that removes the then-unused
interfaces.

So if you can pick up the xfs patches, that would help me.

> The y2038 format changes are going to take a while to push through
> review.  If somehow it all gets through review for 5.6 I can always
> apply both and fix the merge damage, but more likely y2038 timestamps is
> a <cough> 5.8 EXPERIMENTAL thing.
>
> Or later, given that Dave and I both have years worth of unreviewed
> patch backlog. :(

Ok, I see.

        Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-17 15:02       ` Arnd Bergmann
@ 2019-12-17 22:15         ` Darrick J. Wong
  2019-12-18 16:44           ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Darrick J. Wong @ 2019-12-17 22:15 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Carlos Maiolino, Pavel Reichl, Eric Sandeen, Dave Chinner,
	Allison Collins, Jan Kara

On Tue, Dec 17, 2019 at 04:02:47PM +0100, Arnd Bergmann wrote:
> On Mon, Dec 16, 2019 at 5:52 PM Arnd Bergmann <arnd@arndb.de> wrote:
> > On Fri, Dec 13, 2019 at 10:17 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
> >>
> >> Hmm, so one thing that I clean up on the way to bigtime is the total
> >> lack of clamping here.  If (for example) it's September 2105 and
> >> rtbtimelimit is set to 1 year, this will cause an integer overflow.  The
> >> quota timer will be set to 1970 and expire immediately, rather than what
> >> I'd consider the best effort of February 2106.
> 
> One more hing to note (I will add this to the changelog text) is that on

Ok, I'll look for it in the next revision you send out.

By the way, would you mind cc'ing the xfs list on all 24 patches?  They
probably aren't directly relevant to xfs, but it does make it a lot
easier for us to look at the other 21 patches and think "Oh, ok, so
there isn't some core infrastructure change that we're not seeing".

> 32-bit architectures, the limit here is y2038, while on 64-bit
> architectures it's y2106:

Yikes.  I probably just need to send the bigtime series and see what you
all think about the mess I created^W^W^Wway I dealt with all that.

> int xfs_trans_dqresv(...)
> {
>        time_t                  timer; /* signed 'long' */
>        timer = be32_to_cpu(dqp->q_core.d_btimer);
>        /* get_seconds() returns unsigned long */
>       if ((timer != 0 && get_seconds() > timer))
>                 return -EDQUOT;
> }
> 
> > I don't think clamping would be good here, that just replaces
> > one bug with another at the overflow time. If you would like to
> > have something better before this gets extended, I could try to
> > come up with a version that converts it to the nearest 64-bit
> > timestamp, similar to the way that time_before32() in the kernel
> > or the NTP protocol work.
> >
> > If you think it can get extended properly soon, I'd just leave the
> > patch as it is today in order to remove the get_seconds()
> > interface for v5.6.
> 
> I've tried this now, and but this feels wrong: it adds lots of complexity
> for corner cases and is still fragile, e.g. when the time is wrong
> during boot before ntp runs. See that patch below for reference.

Yeah, that is pretty weird to glue the upper 32 bits of the timestamp
onto the expiration timer...

--D

> I also see that quotatool on xfs always uses the old xfs quota
> interface, so it already overflows on the user space side. Fixing
> this properly seems to be a bigger effort than I was planning for
> (on an unpatched 64-bit kernel):
> 
> $ sudo quotatool -b    -u  -t 220month  /mnt/tmp -r
> $ rm file ; fallocate -l 11M file
> $ sudo quotatool -d /mnt/tmp -u arnd
> 1000 /mnt/tmp 11264 10240 20480 570239975 2 0 00
> $ sudo quotatool -b    -u  -t 222month  /mnt/tmp -r
> $ rm file ; fallocate -l 11M file
> $ sudo quotatool -d /mnt/tmp -u arnd
> 1000 /mnt/tmp 11264 10240 20480 18446744069990008316 2 0 00
> 
>        Arnd
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 9cfd3209f52b..6c9128bb607b 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -98,6 +98,23 @@ xfs_qm_adjust_dqlimits(
>                 xfs_dquot_set_prealloc_limits(dq);
>  }
> 
> +static __be32 xfs_quota_timeout32(s64 limit)
> +{
> +       time64_t now = ktime_get_real_seconds();
> +       u32 timeout;
> +
> +       /* avoid overflows in out-of-range limits */
> +       if ((u64)limit > S32_MAX)
> +               limit = S32_MAX;
> +       timeout = now + limit;
> +
> +       /* avoid timeout of zero */
> +       if (lower_32_bits(timeout) == 0)
> +               return cpu_to_be32(1);
> +
> +       return cpu_to_be32(lower_32_bits(timeout));
> +}
> +
>  /*
>   * Check the limits and timers of a dquot and start or reset timers
>   * if necessary.
> @@ -137,7 +154,7 @@ xfs_qm_adjust_dqtimers(
>                     (d->d_blk_hardlimit &&
>                      (be64_to_cpu(d->d_bcount) >
>                       be64_to_cpu(d->d_blk_hardlimit)))) {
> -                       d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
> +                       d->d_btimer = xfs_quota_timeout32(
>                                         mp->m_quotainfo->qi_btimelimit);
>                 } else {
>                         d->d_bwarns = 0;
> @@ -160,7 +177,7 @@ xfs_qm_adjust_dqtimers(
>                     (d->d_ino_hardlimit &&
>                      (be64_to_cpu(d->d_icount) >
>                       be64_to_cpu(d->d_ino_hardlimit)))) {
> -                       d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
> +                       d->d_itimer = xfs_quota_timeout32(
>                                         mp->m_quotainfo->qi_itimelimit);
>                 } else {
>                         d->d_iwarns = 0;
> @@ -183,7 +200,7 @@ xfs_qm_adjust_dqtimers(
>                     (d->d_rtb_hardlimit &&
>                      (be64_to_cpu(d->d_rtbcount) >
>                       be64_to_cpu(d->d_rtb_hardlimit)))) {
> -                       d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
> +                       d->d_rtbtimer = xfs_quota_timeout32(
>                                         mp->m_quotainfo->qi_rtbtimelimit);
>                 } else {
>                         d->d_rtbwarns = 0;
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 1ea82764bf89..2087626b4bee 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -601,6 +601,14 @@ xfs_qm_scall_setqlim(
>         return error;
>  }
> 
> +/* Assume timers are within +/- 68 years of current wall clock */
> +static time64_t xfs_quota_time32_to_time64(time64_t now, __be32 timer)
> +{
> +       s32 diff = be32_to_cpu(timer) - lower_32_bits(now);
> +
> +       return now + diff;
> +}
> +
>  /* Fill out the quota context. */
>  static void
>  xfs_qm_scall_getquota_fill_qc(
> @@ -609,6 +617,8 @@ xfs_qm_scall_getquota_fill_qc(
>         const struct xfs_dquot  *dqp,
>         struct qc_dqblk         *dst)
>  {
> +       time64_t now = ktime_get_real_seconds();
> +
>         memset(dst, 0, sizeof(*dst));
>         dst->d_spc_hardlimit =
>                 XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
> @@ -618,8 +628,8 @@ xfs_qm_scall_getquota_fill_qc(
>         dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
>         dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount);
>         dst->d_ino_count = dqp->q_res_icount;
> -       dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer);
> -       dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer);
> +       dst->d_spc_timer = xfs_quota_time32_to_time64(now,
> dqp->q_core.d_btimer);
> +       dst->d_ino_timer = xfs_quota_time32_to_time64(now,
> dqp->q_core.d_itimer);
>         dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns);
>         dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns);
>         dst->d_rt_spc_hardlimit =
> @@ -627,7 +637,7 @@ xfs_qm_scall_getquota_fill_qc(
>         dst->d_rt_spc_softlimit =
>                 XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
>         dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount);
> -       dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
> +       dst->d_rt_spc_timer = xfs_quota_time32_to_time64(now,
> dqp->q_core.d_rtbtimer);
>         dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
> 
>         /*
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index d1b9869bc5fa..c75887da6546 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -636,7 +636,8 @@ xfs_trans_dqresv(
>                         }
>                         if (softlimit && total_count > softlimit) {
>                                 if ((timer != 0 &&
> -                                    ktime_get_real_seconds() > timer) ||
> +                                    time_after32(ktime_get_real_seconds(),
> +                                                 timer)) ||
>                                     (warns != 0 && warns >= warnlimit)) {
>                                         xfs_quota_warn(mp, dqp,
>                                                        QUOTA_NL_BSOFTLONGWARN);
> @@ -664,7 +665,8 @@ xfs_trans_dqresv(
>                         }
>                         if (softlimit && total_count > softlimit) {
>                                 if  ((timer != 0 &&
> -                                     ktime_get_real_seconds() > timer) ||
> +                                    time_after32(ktime_get_real_seconds(),
> +                                                 timer)) ||
>                                      (warns != 0 && warns >= warnlimit)) {
>                                         xfs_quota_warn(mp, dqp,
>                                                        QUOTA_NL_ISOFTLONGWARN);

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 21/24] xfs: quota: move to time64_t interfaces
  2019-12-17 22:15         ` Darrick J. Wong
@ 2019-12-18 16:44           ` Arnd Bergmann
  0 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2019-12-18 16:44 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: y2038 Mailman List, linux-kernel, linux-xfs, Brian Foster,
	Carlos Maiolino, Pavel Reichl, Eric Sandeen, Dave Chinner,
	Allison Collins, Jan Kara

On Tue, Dec 17, 2019 at 11:18 PM Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Tue, Dec 17, 2019 at 04:02:47PM +0100, Arnd Bergmann wrote:
> > On Mon, Dec 16, 2019 at 5:52 PM Arnd Bergmann <arnd@arndb.de> wrote:
> > > On Fri, Dec 13, 2019 at 10:17 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
> > >>
> > >> Hmm, so one thing that I clean up on the way to bigtime is the total
> > >> lack of clamping here.  If (for example) it's September 2105 and
> > >> rtbtimelimit is set to 1 year, this will cause an integer overflow.  The
> > >> quota timer will be set to 1970 and expire immediately, rather than what
> > >> I'd consider the best effort of February 2106.
> >
> > One more hing to note (I will add this to the changelog text) is that on
>
> Ok, I'll look for it in the next revision you send out.
>
> By the way, would you mind cc'ing the xfs list on all 24 patches?  They
> probably aren't directly relevant to xfs, but it does make it a lot
> easier for us to look at the other 21 patches and think "Oh, ok, so
> there isn't some core infrastructure change that we're not seeing".

I wasn't planning on sending the full series once more, as there were very
few comments now. I've sent the three XFS patches again by themselves
now. If you can pick these up, I'll put the rest into linux-next to give them
some more testing, and hopefully have others pick up a couple more
before I send a pull request.

      Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Y2038] [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2019-12-13 20:53 ` [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC Arnd Bergmann
@ 2020-01-08  1:16   ` Ben Hutchings
  2020-01-17 15:47   ` Guido Günther
  1 sibling, 0 replies; 46+ messages in thread
From: Ben Hutchings @ 2020-01-08  1:16 UTC (permalink / raw)
  To: Arnd Bergmann, y2038, linux-kernel, Lucas Stach, David Airlie,
	Daniel Vetter
  Cc: Guido Günther, etnaviv, dri-devel, Christian Gmeiner,
	Philipp Zabel, Russell King, Sam Ravnborg, Emil Velikov

On Fri, 2019-12-13 at 21:53 +0100, Arnd Bergmann wrote:
> Most kernel interfaces that take a timespec require normalized
> representation with tv_nsec between 0 and NSEC_PER_SEC.
> 
> Passing values larger than 0x100000000ull further behaves differently
> on 32-bit and 64-bit kernels, and can cause the latter to spend a long
> time counting seconds in timespec64_sub()/set_normalized_timespec64().
> 
> Reject those large values at the user interface to enforce sane and
> portable behavior.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/gpu/drm/etnaviv/etnaviv_drv.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> index 1f9c01be40d7..95d72dc00280 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> @@ -297,6 +297,9 @@ static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
>  	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
>  		return -EINVAL;
>  
> +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
[...]

There's an off-by-one error between the subject line and the actual
changes.  The subject line seems to have the correct comparison.

Ben.

-- 
Ben Hutchings, Software Developer                         Codethink Ltd
https://www.codethink.co.uk/                 Dale House, 35 Dale Street
                                     Manchester, M1 2HF, United Kingdom


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2019-12-13 20:53 ` [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC Arnd Bergmann
  2020-01-08  1:16   ` [Y2038] " Ben Hutchings
@ 2020-01-17 15:47   ` Guido Günther
  2020-01-20 17:47     ` Lucas Stach
  1 sibling, 1 reply; 46+ messages in thread
From: Guido Günther @ 2020-01-17 15:47 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, linux-kernel, Lucas Stach, David Airlie, Daniel Vetter,
	etnaviv, dri-devel, Christian Gmeiner, Philipp Zabel,
	Russell King, Sam Ravnborg, Emil Velikov

Hi,
On Fri, Dec 13, 2019 at 09:53:41PM +0100, Arnd Bergmann wrote:
> Most kernel interfaces that take a timespec require normalized
> representation with tv_nsec between 0 and NSEC_PER_SEC.
> 
> Passing values larger than 0x100000000ull further behaves differently
> on 32-bit and 64-bit kernels, and can cause the latter to spend a long
> time counting seconds in timespec64_sub()/set_normalized_timespec64().
> 
> Reject those large values at the user interface to enforce sane and
> portable behavior.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/gpu/drm/etnaviv/etnaviv_drv.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> index 1f9c01be40d7..95d72dc00280 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> @@ -297,6 +297,9 @@ static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
>  	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
>  		return -EINVAL;
>  
> +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> +		return -EINVAL;
> +
>  	obj = drm_gem_object_lookup(file, args->handle);
>  	if (!obj)
>  		return -ENOENT;
> @@ -360,6 +363,9 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
>  	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
>  		return -EINVAL;
>  
> +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> +		return -EINVAL;
> +
>  	if (args->pipe >= ETNA_MAX_PIPES)
>  		return -EINVAL;
>  
> @@ -411,6 +417,9 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
>  	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
>  		return -EINVAL;
>  
> +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> +		return -EINVAL;
> +
>  	if (args->pipe >= ETNA_MAX_PIPES)
>  		return -EINVAL;
>

This breaks rendering here on arm64/gc7000 due to

ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0

This is due to

    get_abs_timeout(&req.timeout, 5000000000);

in etna_bo_cpu_prep which can exceed NSEC_PER_SEC.

Should i send a patch to revert that change since it breaks existing userspace?

Cheers,
 -- Guido

> -- 
> 2.20.0
> 
> _______________________________________________
> etnaviv mailing list
> etnaviv@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/etnaviv
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2020-01-17 15:47   ` Guido Günther
@ 2020-01-20 17:47     ` Lucas Stach
  2020-01-20 18:47       ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Lucas Stach @ 2020-01-20 17:47 UTC (permalink / raw)
  To: Guido Günther, Arnd Bergmann
  Cc: Philipp Zabel, y2038, etnaviv, dri-devel, linux-kernel,
	David Airlie, Christian Gmeiner, Daniel Vetter, Russell King,
	Emil Velikov, Sam Ravnborg

On Fr, 2020-01-17 at 16:47 +0100, Guido Günther wrote:
> Hi,
> On Fri, Dec 13, 2019 at 09:53:41PM +0100, Arnd Bergmann wrote:
> > Most kernel interfaces that take a timespec require normalized
> > representation with tv_nsec between 0 and NSEC_PER_SEC.
> > 
> > Passing values larger than 0x100000000ull further behaves differently
> > on 32-bit and 64-bit kernels, and can cause the latter to spend a long
> > time counting seconds in timespec64_sub()/set_normalized_timespec64().
> > 
> > Reject those large values at the user interface to enforce sane and
> > portable behavior.
> > 
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> >  drivers/gpu/drm/etnaviv/etnaviv_drv.c | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> > index 1f9c01be40d7..95d72dc00280 100644
> > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> > @@ -297,6 +297,9 @@ static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
> >  	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
> >  		return -EINVAL;
> >  
> > +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> > +		return -EINVAL;
> > +
> >  	obj = drm_gem_object_lookup(file, args->handle);
> >  	if (!obj)
> >  		return -ENOENT;
> > @@ -360,6 +363,9 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
> >  	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
> >  		return -EINVAL;
> >  
> > +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> > +		return -EINVAL;
> > +
> >  	if (args->pipe >= ETNA_MAX_PIPES)
> >  		return -EINVAL;
> >  
> > @@ -411,6 +417,9 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
> >  	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
> >  		return -EINVAL;
> >  
> > +	if (args->timeout.tv_nsec > NSEC_PER_SEC)
> > +		return -EINVAL;
> > +
> >  	if (args->pipe >= ETNA_MAX_PIPES)
> >  		return -EINVAL;
> > 
> 
> This breaks rendering here on arm64/gc7000 due to
> 
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> 
> This is due to
> 
>     get_abs_timeout(&req.timeout, 5000000000);
> 
> in etna_bo_cpu_prep which can exceed NSEC_PER_SEC.
> 
> Should i send a patch to revert that change since it breaks existing userspace?

No need to revert. This patch has not been applied to the etnaviv tree
yet, I guess it's just in one of Arnds branches feeding into -next.

That part of userspace is pretty dumb, as it misses to renormalize
tv_nsec when it overflows the second boundary. So if what I see is
correct it should be enough to allow 2 * NSEC_PER_SEC, which should
both reject broken large timeout and keep existing userspace working.

Regards,
Lucas


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2020-01-20 17:47     ` Lucas Stach
@ 2020-01-20 18:47       ` Arnd Bergmann
  2020-01-21 10:21         ` Lucas Stach
  0 siblings, 1 reply; 46+ messages in thread
From: Arnd Bergmann @ 2020-01-20 18:47 UTC (permalink / raw)
  To: Lucas Stach
  Cc: Guido Günther, Philipp Zabel, y2038 Mailman List,
	The etnaviv authors, dri-devel, linux-kernel, David Airlie,
	Christian Gmeiner, Daniel Vetter, Russell King, Emil Velikov,
	Sam Ravnborg

On Mon, Jan 20, 2020 at 6:48 PM Lucas Stach <l.stach@pengutronix.de> wrote:
> On Fr, 2020-01-17 at 16:47 +0100, Guido Günther wrote:
> >
> > This breaks rendering here on arm64/gc7000 due to
> >
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> >
> > This is due to
> >
> >     get_abs_timeout(&req.timeout, 5000000000);
> >
> > in etna_bo_cpu_prep which can exceed NSEC_PER_SEC.
> >
> > Should i send a patch to revert that change since it breaks existing userspace?
>
> No need to revert. This patch has not been applied to the etnaviv tree
> yet, I guess it's just in one of Arnds branches feeding into -next.
>
> That part of userspace is pretty dumb, as it misses to renormalize
> tv_nsec when it overflows the second boundary. So if what I see is
> correct it should be enough to allow 2 * NSEC_PER_SEC, which should
> both reject broken large timeout and keep existing userspace working.

Ah, so it's never more than 2 billion nanoseconds in known user space?
I can definitely change my patch (actually add one on top) to allow that
and handle it as before, or alternatively accept any 64-bit nanosecond value
as arm64 already did, but make it less inefficient to handle.

       Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2020-01-20 18:47       ` Arnd Bergmann
@ 2020-01-21 10:21         ` Lucas Stach
  2020-01-21 11:46           ` Arnd Bergmann
  0 siblings, 1 reply; 46+ messages in thread
From: Lucas Stach @ 2020-01-21 10:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Guido Günther, Philipp Zabel, y2038 Mailman List,
	The etnaviv authors, dri-devel, linux-kernel, David Airlie,
	Christian Gmeiner, Daniel Vetter, Russell King, Emil Velikov,
	Sam Ravnborg

On Mo, 2020-01-20 at 19:47 +0100, Arnd Bergmann wrote:
> On Mon, Jan 20, 2020 at 6:48 PM Lucas Stach <l.stach@pengutronix.de> wrote:
> > On Fr, 2020-01-17 at 16:47 +0100, Guido Günther wrote:
> > > This breaks rendering here on arm64/gc7000 due to
> > > 
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > 
> > > This is due to
> > > 
> > >     get_abs_timeout(&req.timeout, 5000000000);
> > > 
> > > in etna_bo_cpu_prep which can exceed NSEC_PER_SEC.
> > > 
> > > Should i send a patch to revert that change since it breaks existing userspace?
> > 
> > No need to revert. This patch has not been applied to the etnaviv tree
> > yet, I guess it's just in one of Arnds branches feeding into -next.
> > 
> > That part of userspace is pretty dumb, as it misses to renormalize
> > tv_nsec when it overflows the second boundary. So if what I see is
> > correct it should be enough to allow 2 * NSEC_PER_SEC, which should
> > both reject broken large timeout and keep existing userspace working.
> 
> Ah, so it's never more than 2 billion nanoseconds in known user space?
> I can definitely change my patch (actually add one on top) to allow that
> and handle it as before, or alternatively accept any 64-bit nanosecond value
> as arm64 already did, but make it less inefficient to handle.

So the broken userspace code looks like this:

static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns)
{
        struct timespec t;
        uint32_t s = ns / 1000000000;
        clock_gettime(CLOCK_MONOTONIC, &t);
        tv->tv_sec = t.tv_sec + s;
        tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000);
}

Which means it _tries_ to do the right thing by putting the billion
part into the tv_sec member and only the remaining ns part is added to
tv_nsec, but then it fails to propagate a tv_nsec overflow over
NSEC_PER_SEC into tv_sec.

Which means the tv_nsec should never be more than 2 * NSEC_PER_SEC in
known userspace. I would prefer if we could make the interface as
strict as possible (i.e. no arbitrary large numbers in tv_nsec), while
keeping this specific corner case working.

Regards,
Lucas


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC
  2020-01-21 10:21         ` Lucas Stach
@ 2020-01-21 11:46           ` Arnd Bergmann
  0 siblings, 0 replies; 46+ messages in thread
From: Arnd Bergmann @ 2020-01-21 11:46 UTC (permalink / raw)
  To: Lucas Stach
  Cc: Guido Günther, Philipp Zabel, y2038 Mailman List,
	The etnaviv authors, dri-devel, linux-kernel, David Airlie,
	Christian Gmeiner, Daniel Vetter, Russell King, Emil Velikov,
	Sam Ravnborg

On Tue, Jan 21, 2020 at 11:22 AM Lucas Stach <l.stach@pengutronix.de> wrote:
>
> On Mo, 2020-01-20 at 19:47 +0100, Arnd Bergmann wrote:
> > On Mon, Jan 20, 2020 at 6:48 PM Lucas Stach <l.stach@pengutronix.de> wrote:
> > > On Fr, 2020-01-17 at 16:47 +0100, Guido Günther wrote:
> > > > This breaks rendering here on arm64/gc7000 due to
> > > >
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_PREP or DRM_IOCTL_MSM_GEM_CPU_PREP, 0xfffff7888680) = -1 EINVAL (Invalid argument)
> > > > ioctl(6, DRM_IOCTL_ETNAVIV_GEM_CPU_FINI or DRM_IOCTL_QXL_CLIENTCAP, 0xfffff78885e0) = 0
> > > >
> > > > This is due to
> > > >
> > > >     get_abs_timeout(&req.timeout, 5000000000);
> > > >
> > > > in etna_bo_cpu_prep which can exceed NSEC_PER_SEC.
> > > >
> > > > Should i send a patch to revert that change since it breaks existing userspace?
> > >
> > > No need to revert. This patch has not been applied to the etnaviv tree
> > > yet, I guess it's just in one of Arnds branches feeding into -next.
> > >
> > > That part of userspace is pretty dumb, as it misses to renormalize
> > > tv_nsec when it overflows the second boundary. So if what I see is
> > > correct it should be enough to allow 2 * NSEC_PER_SEC, which should
> > > both reject broken large timeout and keep existing userspace working.
> >
> > Ah, so it's never more than 2 billion nanoseconds in known user space?
> > I can definitely change my patch (actually add one on top) to allow that
> > and handle it as before, or alternatively accept any 64-bit nanosecond value
> > as arm64 already did, but make it less inefficient to handle.
>
> So the broken userspace code looks like this:
>
> static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns)
> {
>         struct timespec t;
>         uint32_t s = ns / 1000000000;
>         clock_gettime(CLOCK_MONOTONIC, &t);
>         tv->tv_sec = t.tv_sec + s;
>         tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000);
> }
>
> Which means it _tries_ to do the right thing by putting the billion
> part into the tv_sec member and only the remaining ns part is added to
> tv_nsec, but then it fails to propagate a tv_nsec overflow over
> NSEC_PER_SEC into tv_sec.
>
> Which means the tv_nsec should never be more than 2 * NSEC_PER_SEC in
> known userspace. I would prefer if we could make the interface as
> strict as possible (i.e. no arbitrary large numbers in tv_nsec), while
> keeping this specific corner case working.

I've added a patch on top of my 2038 branch, please have a look at that.

      Arnd

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2020-01-21 11:46 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-13 20:49 [PATCH v2 00/24] drivers, fs: y2038 updates Arnd Bergmann
2019-12-13 20:49 ` [PATCH v2 01/24] Input: input_event: fix struct padding on sparc64 Arnd Bergmann
2019-12-13 22:08   ` Dmitry Torokhov
2019-12-13 20:49 ` [PATCH v2 02/24] fat: use prandom_u32() for i_generation Arnd Bergmann
2019-12-13 20:49 ` [PATCH v2 03/24] dlm: use SO_SNDTIMEO_NEW instead of SO_SNDTIMEO_OLD Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 04/24] xtensa: ISS: avoid struct timeval Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 05/24] um: ubd: use 64-bit time_t where possible Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 06/24] acct: stop using get_seconds() Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 07/24] tsacct: add 64-bit btime field Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 08/24] packet: clarify timestamp overflow Arnd Bergmann
2019-12-13 20:52 ` [PATCH v2 09/24] quota: avoid time_t in v1_disk_dqblk definition Arnd Bergmann
2019-12-16 13:14   ` Jan Kara
2019-12-13 20:53 ` [PATCH v2 10/24] hostfs: pass 64-bit timestamps to/from user space Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 11/24] hfs/hfsplus: use 64-bit inode timestamps Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 12/24] drm/msm: avoid using 'timespec' Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 13/24] drm/etnaviv: reject timeouts with tv_nsec >= NSEC_PER_SEC Arnd Bergmann
2020-01-08  1:16   ` [Y2038] " Ben Hutchings
2020-01-17 15:47   ` Guido Günther
2020-01-20 17:47     ` Lucas Stach
2020-01-20 18:47       ` Arnd Bergmann
2020-01-21 10:21         ` Lucas Stach
2020-01-21 11:46           ` Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 14/24] drm/etnaviv: avoid deprecated timespec Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 15/24] sunrpc: convert to time64_t for expiry Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 16/24] nfs: use time64_t internally Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 17/24] nfs: fix timstamp debug prints Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 18/24] nfs: fscache: use timespec64 in inode auxdata Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 19/24] xfs: rename compat_time_t to old_time32_t Arnd Bergmann
2019-12-13 21:18   ` Darrick J. Wong
2019-12-16 16:31     ` Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 20/24] xfs: disallow broken ioctls without compat-32-bit-time Arnd Bergmann
2019-12-13 21:05   ` Darrick J. Wong
2019-12-16 16:45     ` Arnd Bergmann
2019-12-16 16:52       ` Darrick J. Wong
2019-12-17 15:06         ` Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 21/24] xfs: quota: move to time64_t interfaces Arnd Bergmann
2019-12-13 21:17   ` Darrick J. Wong
2019-12-16 16:52     ` Arnd Bergmann
2019-12-17 15:02       ` Arnd Bergmann
2019-12-17 22:15         ` Darrick J. Wong
2019-12-18 16:44           ` Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 22/24] y2038: remove obsolete jiffies conversion functions Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 23/24] y2038: rename itimerval to __kernel_old_itimerval Arnd Bergmann
2019-12-13 20:53 ` [PATCH v2 24/24] y2038: sparc: remove use of struct timex Arnd Bergmann
2019-12-14  1:37   ` Julian Calaby
2019-12-14 14:44     ` [Y2038] " Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).