2019-04-16 20:38:04

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
socket protocol handlers, and all of those end up calling the same
sock_get_timestamp()/sock_get_timestampns() helper functions, which
results in a lot of duplicate code.

With the introduction of 64-bit time_t on 32-bit architectures, this
gets worse, as we then need four different ioctl commands in each
socket protocol implementation.

To simplify that, let's add a new .gettstamp() operation in
struct proto_ops, and move ioctl implementation into the common
sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
through.

We can reuse the sock_get_timestamp() implementation, but generalize
it so it can deal with both native and compat mode, as well as
timeval and timespec structures.

Acked-by: Stefan Schmidt <[email protected]>
Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
Signed-off-by: Arnd Bergmann <[email protected]>
---
v2: reworked to not break sparc64 support
---
include/linux/net.h | 2 ++
include/net/compat.h | 3 --
include/net/sock.h | 4 +--
net/appletalk/ddp.c | 7 +----
net/atm/ioctl.c | 16 ----------
net/atm/pvc.c | 1 +
net/atm/svc.c | 1 +
net/ax25/af_ax25.c | 9 +-----
net/bluetooth/af_bluetooth.c | 8 -----
net/bluetooth/l2cap_sock.c | 1 +
net/bluetooth/rfcomm/sock.c | 1 +
net/bluetooth/sco.c | 1 +
net/can/af_can.c | 6 ----
net/can/bcm.c | 1 +
net/can/raw.c | 1 +
net/compat.c | 57 ------------------------------------
net/core/sock.c | 51 +++++++++++++++++---------------
net/dccp/ipv4.c | 1 +
net/dccp/ipv6.c | 1 +
net/ieee802154/socket.c | 6 ++--
net/ipv4/af_inet.c | 9 ++----
net/ipv6/af_inet6.c | 8 ++---
net/ipv6/raw.c | 1 +
net/l2tp/l2tp_ip.c | 1 +
net/l2tp/l2tp_ip6.c | 1 +
net/netrom/af_netrom.c | 14 +--------
net/packet/af_packet.c | 7 ++---
net/qrtr/qrtr.c | 4 +--
net/rose/af_rose.c | 7 +----
net/sctp/ipv6.c | 1 +
net/sctp/protocol.c | 1 +
net/socket.c | 48 +++++++++---------------------
net/x25/af_x25.c | 27 +----------------
33 files changed, 75 insertions(+), 232 deletions(-)

diff --git a/include/linux/net.h b/include/linux/net.h
index c606c72311d0..50bf5206ead6 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -161,6 +161,8 @@ struct proto_ops {
int (*compat_ioctl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
#endif
+ int (*gettstamp) (struct socket *sock, void __user *userstamp,
+ bool timeval, bool time32);
int (*listen) (struct socket *sock, int len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt)(struct socket *sock, int level,
diff --git a/include/net/compat.h b/include/net/compat.h
index 4c6d75612b6c..f277653c7e17 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -30,9 +30,6 @@ struct compat_cmsghdr {
compat_int_t cmsg_type;
};

-int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
-int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
-
#else /* defined(CONFIG_COMPAT) */
/*
* To avoid compiler warnings:
diff --git a/include/net/sock.h b/include/net/sock.h
index 8de5ee258b93..d1fe105dcf42 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1607,6 +1607,8 @@ int sock_setsockopt(struct socket *sock, int level, int op,

int sock_getsockopt(struct socket *sock, int level, int op,
char __user *optval, int __user *optlen);
+int sock_gettstamp(struct socket *sock, void __user *userstamp,
+ bool timeval, bool time32);
struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
int noblock, int *errcode);
struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
@@ -2493,8 +2495,6 @@ static inline bool sk_listener(const struct sock *sk)
}

void sock_enable_timestamp(struct sock *sk, int flag);
-int sock_get_timestamp(struct sock *, struct timeval __user *);
-int sock_get_timestampns(struct sock *, struct timespec __user *);
int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level,
int type);

diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 709d2542f729..e2511027d19b 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1806,12 +1806,6 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
rc = put_user(amount, (int __user *)argp);
break;
}
- case SIOCGSTAMP:
- rc = sock_get_timestamp(sk, argp);
- break;
- case SIOCGSTAMPNS:
- rc = sock_get_timestampns(sk, argp);
- break;
/* Routing */
case SIOCADDRT:
case SIOCDELRT:
@@ -1871,6 +1865,7 @@ static const struct proto_ops atalk_dgram_ops = {
.getname = atalk_getname,
.poll = datagram_poll,
.ioctl = atalk_ioctl,
+ .gettstamp = sock_gettstamp,
#ifdef CONFIG_COMPAT
.compat_ioctl = atalk_compat_ioctl,
#endif
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 2ff0e5e470e3..d955b683aa7c 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -81,22 +81,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
(int __user *)argp) ? -EFAULT : 0;
goto done;
}
- case SIOCGSTAMP: /* borrowed from IP */
-#ifdef CONFIG_COMPAT
- if (compat)
- error = compat_sock_get_timestamp(sk, argp);
- else
-#endif
- error = sock_get_timestamp(sk, argp);
- goto done;
- case SIOCGSTAMPNS: /* borrowed from IP */
-#ifdef CONFIG_COMPAT
- if (compat)
- error = compat_sock_get_timestampns(sk, argp);
- else
-#endif
- error = sock_get_timestampns(sk, argp);
- goto done;
case ATM_SETSC:
net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
current->comm, task_pid_nr(current));
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index 2cb10af16afc..02bd2a436bdf 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -118,6 +118,7 @@ static const struct proto_ops pvc_proto_ops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = vcc_compat_ioctl,
#endif
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = pvc_shutdown,
.setsockopt = pvc_setsockopt,
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 2f91b766ac42..908cbb8654f5 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -641,6 +641,7 @@ static const struct proto_ops svc_proto_ops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = svc_compat_ioctl,
#endif
+ .gettstamp = sock_gettstamp,
.listen = svc_listen,
.shutdown = svc_shutdown,
.setsockopt = svc_setsockopt,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 5d01edf8d819..449e7b7190c1 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1714,14 +1714,6 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}

- case SIOCGSTAMP:
- res = sock_get_timestamp(sk, argp);
- break;
-
- case SIOCGSTAMPNS:
- res = sock_get_timestampns(sk, argp);
- break;
-
case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: {
@@ -1950,6 +1942,7 @@ static const struct proto_ops ax25_proto_ops = {
.getname = ax25_getname,
.poll = datagram_poll,
.ioctl = ax25_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = ax25_listen,
.shutdown = ax25_shutdown,
.setsockopt = ax25_setsockopt,
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8d12198eaa94..94ddf19998c7 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -521,14 +521,6 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
err = put_user(amount, (int __user *) arg);
break;

- case SIOCGSTAMP:
- err = sock_get_timestamp(sk, (struct timeval __user *) arg);
- break;
-
- case SIOCGSTAMPNS:
- err = sock_get_timestampns(sk, (struct timespec __user *) arg);
- break;
-
default:
err = -ENOIOCTLCMD;
break;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index a3a2cd55e23a..dcb14abebeba 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1655,6 +1655,7 @@ static const struct proto_ops l2cap_sock_ops = {
.recvmsg = l2cap_sock_recvmsg,
.poll = bt_sock_poll,
.ioctl = bt_sock_ioctl,
+ .gettstamp = sock_gettstamp,
.mmap = sock_no_mmap,
.socketpair = sock_no_socketpair,
.shutdown = l2cap_sock_shutdown,
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index b1f49fcc0478..90bb53aa4bee 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1039,6 +1039,7 @@ static const struct proto_ops rfcomm_sock_ops = {
.setsockopt = rfcomm_sock_setsockopt,
.getsockopt = rfcomm_sock_getsockopt,
.ioctl = rfcomm_sock_ioctl,
+ .gettstamp = sock_gettstamp,
.poll = bt_sock_poll,
.socketpair = sock_no_socketpair,
.mmap = sock_no_mmap
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 9a580999ca57..d894406a5c3b 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1190,6 +1190,7 @@ static const struct proto_ops sco_sock_ops = {
.recvmsg = sco_sock_recvmsg,
.poll = bt_sock_poll,
.ioctl = bt_sock_ioctl,
+ .gettstamp = sock_gettstamp,
.mmap = sock_no_mmap,
.socketpair = sock_no_socketpair,
.shutdown = sco_sock_shutdown,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 1684ba5b51eb..e8fd5dc1780a 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -89,13 +89,7 @@ static atomic_t skbcounter = ATOMIC_INIT(0);

int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- struct sock *sk = sock->sk;
-
switch (cmd) {
-
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *)arg);
-
default:
return -ENOIOCTLCMD;
}
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 79bb8afa9c0c..a34ee52f19ea 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1689,6 +1689,7 @@ static const struct proto_ops bcm_ops = {
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = can_ioctl, /* use can_ioctl() from af_can.c */
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
diff --git a/net/can/raw.c b/net/can/raw.c
index c70207537488..afcbff063a67 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -846,6 +846,7 @@ static const struct proto_ops raw_ops = {
.getname = raw_getname,
.poll = datagram_poll,
.ioctl = can_ioctl, /* use can_ioctl() from af_can.c */
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = raw_setsockopt,
diff --git a/net/compat.c b/net/compat.c
index eeea5eb71639..a031bd333092 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -395,63 +395,6 @@ COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
return __compat_sys_setsockopt(fd, level, optname, optval, optlen);
}

-int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
-{
- struct compat_timeval __user *ctv;
- int err;
- struct timeval tv;
-
- if (COMPAT_USE_64BIT_TIME)
- return sock_get_timestamp(sk, userstamp);
-
- ctv = (struct compat_timeval __user *) userstamp;
- err = -ENOENT;
- sock_enable_timestamp(sk, SOCK_TIMESTAMP);
- tv = ktime_to_timeval(sock_read_timestamp(sk));
-
- if (tv.tv_sec == -1)
- return err;
- if (tv.tv_sec == 0) {
- ktime_t kt = ktime_get_real();
- sock_write_timestamp(sk, kt);
- tv = ktime_to_timeval(kt);
- }
- err = 0;
- if (put_user(tv.tv_sec, &ctv->tv_sec) ||
- put_user(tv.tv_usec, &ctv->tv_usec))
- err = -EFAULT;
- return err;
-}
-EXPORT_SYMBOL(compat_sock_get_timestamp);
-
-int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
-{
- struct compat_timespec __user *ctv;
- int err;
- struct timespec ts;
-
- if (COMPAT_USE_64BIT_TIME)
- return sock_get_timestampns (sk, userstamp);
-
- ctv = (struct compat_timespec __user *) userstamp;
- err = -ENOENT;
- sock_enable_timestamp(sk, SOCK_TIMESTAMP);
- ts = ktime_to_timespec(sock_read_timestamp(sk));
- if (ts.tv_sec == -1)
- return err;
- if (ts.tv_sec == 0) {
- ktime_t kt = ktime_get_real();
- sock_write_timestamp(sk, kt);
- ts = ktime_to_timespec(kt);
- }
- err = 0;
- if (put_user(ts.tv_sec, &ctv->tv_sec) ||
- put_user(ts.tv_nsec, &ctv->tv_nsec))
- err = -EFAULT;
- return err;
-}
-EXPORT_SYMBOL(compat_sock_get_timestampns);
-
static int __compat_sys_getsockopt(int fd, int level, int optname,
char __user *optval,
int __user *optlen)
diff --git a/net/core/sock.c b/net/core/sock.c
index 782343bb925b..dc7c31d66200 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2977,39 +2977,44 @@ bool lock_sock_fast(struct sock *sk)
}
EXPORT_SYMBOL(lock_sock_fast);

-int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
+int sock_gettstamp(struct socket *sock, void __user *userstamp,
+ bool timeval, bool time32)
{
- struct timeval tv;
+ struct sock *sk = sock->sk;
+ struct timespec64 ts;

sock_enable_timestamp(sk, SOCK_TIMESTAMP);
- tv = ktime_to_timeval(sock_read_timestamp(sk));
- if (tv.tv_sec == -1)
+ ts = ktime_to_timespec64(sk->sk_stamp);
+ if (ts.tv_sec == -1)
return -ENOENT;
- if (tv.tv_sec == 0) {
+ if (ts.tv_sec == 0) {
ktime_t kt = ktime_get_real();
- sock_write_timestamp(sk, kt);
- tv = ktime_to_timeval(kt);
+ sock_write_timestamp(sk, kt);;
+ ts = ktime_to_timespec64(kt);
}
- return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
-}
-EXPORT_SYMBOL(sock_get_timestamp);

-int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
-{
- struct timespec ts;
+ if (timeval)
+ ts.tv_nsec /= 1000;

- sock_enable_timestamp(sk, SOCK_TIMESTAMP);
- ts = ktime_to_timespec(sock_read_timestamp(sk));
- if (ts.tv_sec == -1)
- return -ENOENT;
- if (ts.tv_sec == 0) {
- ktime_t kt = ktime_get_real();
- sock_write_timestamp(sk, kt);
- ts = ktime_to_timespec(sk->sk_stamp);
+#ifdef CONFIG_COMPAT_32BIT_TIME
+ if (time32)
+ return put_old_timespec32(&ts, userstamp);
+#endif
+#ifdef CONFIG_SPARC64
+ /* beware of padding in sparc64 timeval */
+ if (timeval && !in_compat_syscall()) {
+ struct __kernel_old_timeval __user tv = {
+ .tv_sec = ts.tv_sec;
+ .tv_usec = ts.tv_nsec;
+ };
+ if (copy_to_user(userstamp, &tv, sizeof(tv))
+ return -EFAULT;
+ return 0;
}
- return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
+#endif
+ return put_timespec64(&ts, userstamp);
}
-EXPORT_SYMBOL(sock_get_timestampns);
+EXPORT_SYMBOL(sock_gettstamp);

void sock_enable_timestamp(struct sock *sk, int flag)
{
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 26a21d97b6b0..004535e4c070 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -991,6 +991,7 @@ static const struct proto_ops inet_dccp_ops = {
/* FIXME: work on tcp_poll to rename it to inet_csk_poll */
.poll = dccp_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
/* FIXME: work on inet_listen to rename it to sock_common_listen */
.listen = inet_dccp_listen,
.shutdown = inet_shutdown,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 57d84e9b7b6f..c4e4d1301062 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1075,6 +1075,7 @@ static const struct proto_ops inet6_dccp_ops = {
.getname = inet6_getname,
.poll = dccp_poll,
.ioctl = inet6_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = inet_dccp_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index bc6b912603f1..ce2dfb997537 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -164,10 +164,6 @@ static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
struct sock *sk = sock->sk;

switch (cmd) {
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *)arg);
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, (struct timespec __user *)arg);
case SIOCGIFADDR:
case SIOCSIFADDR:
return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
@@ -426,6 +422,7 @@ static const struct proto_ops ieee802154_raw_ops = {
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = ieee802154_sock_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_common_setsockopt,
@@ -988,6 +985,7 @@ static const struct proto_ops ieee802154_dgram_ops = {
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = ieee802154_sock_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index eab3ebde981e..0f46d87715aa 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -911,12 +911,6 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct rtentry rt;

switch (cmd) {
- case SIOCGSTAMP:
- err = sock_get_timestamp(sk, (struct timeval __user *)arg);
- break;
- case SIOCGSTAMPNS:
- err = sock_get_timestampns(sk, (struct timespec __user *)arg);
- break;
case SIOCADDRT:
case SIOCDELRT:
if (copy_from_user(&rt, p, sizeof(struct rtentry)))
@@ -988,6 +982,7 @@ const struct proto_ops inet_stream_ops = {
.getname = inet_getname,
.poll = tcp_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = inet_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
@@ -1023,6 +1018,7 @@ const struct proto_ops inet_dgram_ops = {
.getname = inet_getname,
.poll = udp_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
@@ -1055,6 +1051,7 @@ static const struct proto_ops inet_sockraw_ops = {
.getname = inet_getname,
.poll = datagram_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 2f45d2a3e3a3..6d1133fd89f6 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -546,12 +546,6 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct net *net = sock_net(sk);

switch (cmd) {
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *)arg);
-
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, (struct timespec __user *)arg);
-
case SIOCADDRT:
case SIOCDELRT:

@@ -584,6 +578,7 @@ const struct proto_ops inet6_stream_ops = {
.getname = inet6_getname,
.poll = tcp_poll, /* ok */
.ioctl = inet6_ioctl, /* must change */
+ .gettstamp = sock_gettstamp,
.listen = inet_listen, /* ok */
.shutdown = inet_shutdown, /* ok */
.setsockopt = sock_common_setsockopt, /* ok */
@@ -617,6 +612,7 @@ const struct proto_ops inet6_dgram_ops = {
.getname = inet6_getname,
.poll = udp_poll, /* ok */
.ioctl = inet6_ioctl, /* must change */
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen, /* ok */
.shutdown = inet_shutdown, /* ok */
.setsockopt = sock_common_setsockopt, /* ok */
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 5a426226c762..84dbe21b71e5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1356,6 +1356,7 @@ const struct proto_ops inet6_sockraw_ops = {
.getname = inet6_getname,
.poll = datagram_poll, /* ok */
.ioctl = inet6_ioctl, /* must change */
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen, /* ok */
.shutdown = inet_shutdown, /* ok */
.setsockopt = sock_common_setsockopt, /* ok */
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index d4c60523c549..2cac910c1cd4 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -618,6 +618,7 @@ static const struct proto_ops l2tp_ip_ops = {
.getname = l2tp_ip_getname,
.poll = datagram_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 37a69df17cab..4ec546cc1dd6 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -752,6 +752,7 @@ static const struct proto_ops l2tp_ip6_ops = {
.getname = l2tp_ip6_getname,
.poll = datagram_poll,
.ioctl = inet6_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 1d3144d19903..4e97bbbf1916 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1199,7 +1199,6 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
void __user *argp = (void __user *)arg;
- int ret;

switch (cmd) {
case TIOCOUTQ: {
@@ -1225,18 +1224,6 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return put_user(amount, (int __user *)argp);
}

- case SIOCGSTAMP:
- lock_sock(sk);
- ret = sock_get_timestamp(sk, argp);
- release_sock(sk);
- return ret;
-
- case SIOCGSTAMPNS:
- lock_sock(sk);
- ret = sock_get_timestampns(sk, argp);
- release_sock(sk);
- return ret;
-
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1362,6 +1349,7 @@ static const struct proto_ops nr_proto_ops = {
.getname = nr_getname,
.poll = datagram_poll,
.ioctl = nr_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = nr_listen,
.shutdown = sock_no_shutdown,
.setsockopt = nr_setsockopt,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9419c5cf4de5..b012dc5ffb6e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4077,11 +4077,6 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
spin_unlock_bh(&sk->sk_receive_queue.lock);
return put_user(amount, (int __user *)arg);
}
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *)arg);
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, (struct timespec __user *)arg);
-
#ifdef CONFIG_INET
case SIOCADDRT:
case SIOCDELRT:
@@ -4457,6 +4452,7 @@ static const struct proto_ops packet_ops_spkt = {
.getname = packet_getname_spkt,
.poll = datagram_poll,
.ioctl = packet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
@@ -4478,6 +4474,7 @@ static const struct proto_ops packet_ops = {
.getname = packet_getname,
.poll = packet_poll,
.ioctl = packet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = packet_setsockopt,
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index b37e6e0a1026..7c5e8292cc0a 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -968,9 +968,6 @@ static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}
break;
- case SIOCGSTAMP:
- rc = sock_get_timestamp(sk, argp);
- break;
case SIOCADDRT:
case SIOCDELRT:
case SIOCSIFADDR:
@@ -1033,6 +1030,7 @@ static const struct proto_ops qrtr_proto_ops = {
.recvmsg = qrtr_recvmsg,
.getname = qrtr_getname,
.ioctl = qrtr_ioctl,
+ .gettstamp = sock_gettstamp,
.poll = datagram_poll,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index c96f63ffe31e..e274bc6e1458 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1301,12 +1301,6 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return put_user(amount, (unsigned int __user *) argp);
}

- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *) argp);
-
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, (struct timespec __user *) argp);
-
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1474,6 +1468,7 @@ static const struct proto_ops rose_proto_ops = {
.getname = rose_getname,
.poll = datagram_poll,
.ioctl = rose_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = rose_listen,
.shutdown = sock_no_shutdown,
.setsockopt = rose_setsockopt,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 6200cd2b4b99..188c47eb206e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -1030,6 +1030,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
.getname = sctp_getname,
.poll = sctp_poll,
.ioctl = inet6_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sctp_inet_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 951afdeea5e9..f0631bf486b6 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1026,6 +1026,7 @@ static const struct proto_ops inet_seqpacket_ops = {
.getname = inet_getname, /* Semantics are different. */
.poll = sctp_poll,
.ioctl = inet_ioctl,
+ .gettstamp = sock_gettstamp,
.listen = sctp_inet_listen,
.shutdown = inet_shutdown, /* Looks harmless. */
.setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */
diff --git a/net/socket.c b/net/socket.c
index 8255f5bda0aa..ab624d42ead5 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1164,6 +1164,15 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)

err = open_related_ns(&net->ns, get_net_ns);
break;
+ case SIOCGSTAMP:
+ case SIOCGSTAMPNS:
+ if (!sock->ops->gettstamp) {
+ err = -ENOIOCTLCMD;
+ break;
+ }
+ err = sock->ops->gettstamp(sock, argp,
+ cmd == SIOCGSTAMP, false);
+ break;
default:
err = sock_do_ioctl(net, sock, cmd, arg);
break;
@@ -2916,38 +2925,6 @@ void socket_seq_show(struct seq_file *seq)
#endif /* CONFIG_PROC_FS */

#ifdef CONFIG_COMPAT
-static int do_siocgstamp(struct net *net, struct socket *sock,
- unsigned int cmd, void __user *up)
-{
- mm_segment_t old_fs = get_fs();
- struct timeval ktv;
- int err;
-
- set_fs(KERNEL_DS);
- err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
- set_fs(old_fs);
- if (!err)
- err = compat_put_timeval(&ktv, up);
-
- return err;
-}
-
-static int do_siocgstampns(struct net *net, struct socket *sock,
- unsigned int cmd, void __user *up)
-{
- mm_segment_t old_fs = get_fs();
- struct timespec kts;
- int err;
-
- set_fs(KERNEL_DS);
- err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
- set_fs(old_fs);
- if (!err)
- err = compat_put_timespec(&kts, up);
-
- return err;
-}
-
static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
{
struct compat_ifconf ifc32;
@@ -3348,9 +3325,12 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
case SIOCDELRT:
return routing_ioctl(net, sock, cmd, argp);
case SIOCGSTAMP:
- return do_siocgstamp(net, sock, cmd, argp);
case SIOCGSTAMPNS:
- return do_siocgstampns(net, sock, cmd, argp);
+ if (!sock->ops->gettstamp)
+ return -ENOIOCTLCMD;
+ return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP,
+ !COMPAT_USE_64BIT_TIME);
+
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
case SIOCSHWTSTAMP:
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 20a511398389..0ea48a52ce79 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1398,18 +1398,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}

- case SIOCGSTAMP:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestamp(sk,
- (struct timeval __user *)argp);
- break;
- case SIOCGSTAMPNS:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestampns(sk,
- (struct timespec __user *)argp);
- break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1681,8 +1669,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
void __user *argp = compat_ptr(arg);
- struct sock *sk = sock->sk;
-
int rc = -ENOIOCTLCMD;

switch(cmd) {
@@ -1690,18 +1676,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
case TIOCINQ:
rc = x25_ioctl(sock, cmd, (unsigned long)argp);
break;
- case SIOCGSTAMP:
- rc = -EINVAL;
- if (sk)
- rc = compat_sock_get_timestamp(sk,
- (struct timeval __user*)argp);
- break;
- case SIOCGSTAMPNS:
- rc = -EINVAL;
- if (sk)
- rc = compat_sock_get_timestampns(sk,
- (struct timespec __user*)argp);
- break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -1765,6 +1739,7 @@ static const struct proto_ops x25_proto_ops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_x25_ioctl,
#endif
+ .gettstamp = sock_gettstamp,
.listen = x25_listen,
.shutdown = sock_no_shutdown,
.setsockopt = x25_setsockopt,
--
2.20.0



2019-04-17 09:36:58

by Neil Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On Tue, Apr 16, 2019 at 10:32:48PM +0200, Arnd Bergmann wrote:
> The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
> socket protocol handlers, and all of those end up calling the same
> sock_get_timestamp()/sock_get_timestampns() helper functions, which
> results in a lot of duplicate code.
>
> With the introduction of 64-bit time_t on 32-bit architectures, this
> gets worse, as we then need four different ioctl commands in each
> socket protocol implementation.
>
> To simplify that, let's add a new .gettstamp() operation in
> struct proto_ops, and move ioctl implementation into the common
> sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
> through.
>
> We can reuse the sock_get_timestamp() implementation, but generalize
> it so it can deal with both native and compat mode, as well as
> timeval and timespec structures.
>
> Acked-by: Stefan Schmidt <[email protected]>
> Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> v2: reworked to not break sparc64 support
> ---
> include/linux/net.h | 2 ++
> include/net/compat.h | 3 --
> include/net/sock.h | 4 +--
> net/appletalk/ddp.c | 7 +----
> net/atm/ioctl.c | 16 ----------
> net/atm/pvc.c | 1 +
> net/atm/svc.c | 1 +
> net/ax25/af_ax25.c | 9 +-----
> net/bluetooth/af_bluetooth.c | 8 -----
> net/bluetooth/l2cap_sock.c | 1 +
> net/bluetooth/rfcomm/sock.c | 1 +
> net/bluetooth/sco.c | 1 +
> net/can/af_can.c | 6 ----
> net/can/bcm.c | 1 +
> net/can/raw.c | 1 +
> net/compat.c | 57 ------------------------------------
> net/core/sock.c | 51 +++++++++++++++++---------------
> net/dccp/ipv4.c | 1 +
> net/dccp/ipv6.c | 1 +
> net/ieee802154/socket.c | 6 ++--
> net/ipv4/af_inet.c | 9 ++----
> net/ipv6/af_inet6.c | 8 ++---
> net/ipv6/raw.c | 1 +
> net/l2tp/l2tp_ip.c | 1 +
> net/l2tp/l2tp_ip6.c | 1 +
> net/netrom/af_netrom.c | 14 +--------
> net/packet/af_packet.c | 7 ++---
> net/qrtr/qrtr.c | 4 +--
> net/rose/af_rose.c | 7 +----
> net/sctp/ipv6.c | 1 +
> net/sctp/protocol.c | 1 +
> net/socket.c | 48 +++++++++---------------------
> net/x25/af_x25.c | 27 +----------------
> 33 files changed, 75 insertions(+), 232 deletions(-)
>
> diff --git a/include/linux/net.h b/include/linux/net.h
> index c606c72311d0..50bf5206ead6 100644
> --- a/include/linux/net.h
> +++ b/include/linux/net.h
> @@ -161,6 +161,8 @@ struct proto_ops {
> int (*compat_ioctl) (struct socket *sock, unsigned int cmd,
> unsigned long arg);
> #endif
> + int (*gettstamp) (struct socket *sock, void __user *userstamp,
> + bool timeval, bool time32);
> int (*listen) (struct socket *sock, int len);
> int (*shutdown) (struct socket *sock, int flags);
> int (*setsockopt)(struct socket *sock, int level,
> diff --git a/include/net/compat.h b/include/net/compat.h
> index 4c6d75612b6c..f277653c7e17 100644
> --- a/include/net/compat.h
> +++ b/include/net/compat.h
> @@ -30,9 +30,6 @@ struct compat_cmsghdr {
> compat_int_t cmsg_type;
> };
>
> -int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
> -int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
> -
> #else /* defined(CONFIG_COMPAT) */
> /*
> * To avoid compiler warnings:
> diff --git a/include/net/sock.h b/include/net/sock.h
> index 8de5ee258b93..d1fe105dcf42 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -1607,6 +1607,8 @@ int sock_setsockopt(struct socket *sock, int level, int op,
>
> int sock_getsockopt(struct socket *sock, int level, int op,
> char __user *optval, int __user *optlen);
> +int sock_gettstamp(struct socket *sock, void __user *userstamp,
> + bool timeval, bool time32);
> struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
> int noblock, int *errcode);
> struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
> @@ -2493,8 +2495,6 @@ static inline bool sk_listener(const struct sock *sk)
> }
>
> void sock_enable_timestamp(struct sock *sk, int flag);
> -int sock_get_timestamp(struct sock *, struct timeval __user *);
> -int sock_get_timestampns(struct sock *, struct timespec __user *);
> int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level,
> int type);
>
> diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
> index 709d2542f729..e2511027d19b 100644
> --- a/net/appletalk/ddp.c
> +++ b/net/appletalk/ddp.c
> @@ -1806,12 +1806,6 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> rc = put_user(amount, (int __user *)argp);
> break;
> }
> - case SIOCGSTAMP:
> - rc = sock_get_timestamp(sk, argp);
> - break;
> - case SIOCGSTAMPNS:
> - rc = sock_get_timestampns(sk, argp);
> - break;
> /* Routing */
> case SIOCADDRT:
> case SIOCDELRT:
> @@ -1871,6 +1865,7 @@ static const struct proto_ops atalk_dgram_ops = {
> .getname = atalk_getname,
> .poll = datagram_poll,
> .ioctl = atalk_ioctl,
> + .gettstamp = sock_gettstamp,
> #ifdef CONFIG_COMPAT
> .compat_ioctl = atalk_compat_ioctl,
> #endif
> diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
> index 2ff0e5e470e3..d955b683aa7c 100644
> --- a/net/atm/ioctl.c
> +++ b/net/atm/ioctl.c
> @@ -81,22 +81,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
> (int __user *)argp) ? -EFAULT : 0;
> goto done;
> }
> - case SIOCGSTAMP: /* borrowed from IP */
> -#ifdef CONFIG_COMPAT
> - if (compat)
> - error = compat_sock_get_timestamp(sk, argp);
> - else
> -#endif
> - error = sock_get_timestamp(sk, argp);
> - goto done;
> - case SIOCGSTAMPNS: /* borrowed from IP */
> -#ifdef CONFIG_COMPAT
> - if (compat)
> - error = compat_sock_get_timestampns(sk, argp);
> - else
> -#endif
> - error = sock_get_timestampns(sk, argp);
> - goto done;
> case ATM_SETSC:
> net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
> current->comm, task_pid_nr(current));
> diff --git a/net/atm/pvc.c b/net/atm/pvc.c
> index 2cb10af16afc..02bd2a436bdf 100644
> --- a/net/atm/pvc.c
> +++ b/net/atm/pvc.c
> @@ -118,6 +118,7 @@ static const struct proto_ops pvc_proto_ops = {
> #ifdef CONFIG_COMPAT
> .compat_ioctl = vcc_compat_ioctl,
> #endif
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = pvc_shutdown,
> .setsockopt = pvc_setsockopt,
> diff --git a/net/atm/svc.c b/net/atm/svc.c
> index 2f91b766ac42..908cbb8654f5 100644
> --- a/net/atm/svc.c
> +++ b/net/atm/svc.c
> @@ -641,6 +641,7 @@ static const struct proto_ops svc_proto_ops = {
> #ifdef CONFIG_COMPAT
> .compat_ioctl = svc_compat_ioctl,
> #endif
> + .gettstamp = sock_gettstamp,
> .listen = svc_listen,
> .shutdown = svc_shutdown,
> .setsockopt = svc_setsockopt,
> diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
> index 5d01edf8d819..449e7b7190c1 100644
> --- a/net/ax25/af_ax25.c
> +++ b/net/ax25/af_ax25.c
> @@ -1714,14 +1714,6 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> break;
> }
>
> - case SIOCGSTAMP:
> - res = sock_get_timestamp(sk, argp);
> - break;
> -
> - case SIOCGSTAMPNS:
> - res = sock_get_timestampns(sk, argp);
> - break;
> -
> case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
> case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
> case SIOCAX25GETUID: {
> @@ -1950,6 +1942,7 @@ static const struct proto_ops ax25_proto_ops = {
> .getname = ax25_getname,
> .poll = datagram_poll,
> .ioctl = ax25_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = ax25_listen,
> .shutdown = ax25_shutdown,
> .setsockopt = ax25_setsockopt,
> diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
> index 8d12198eaa94..94ddf19998c7 100644
> --- a/net/bluetooth/af_bluetooth.c
> +++ b/net/bluetooth/af_bluetooth.c
> @@ -521,14 +521,6 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> err = put_user(amount, (int __user *) arg);
> break;
>
> - case SIOCGSTAMP:
> - err = sock_get_timestamp(sk, (struct timeval __user *) arg);
> - break;
> -
> - case SIOCGSTAMPNS:
> - err = sock_get_timestampns(sk, (struct timespec __user *) arg);
> - break;
> -
> default:
> err = -ENOIOCTLCMD;
> break;
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index a3a2cd55e23a..dcb14abebeba 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -1655,6 +1655,7 @@ static const struct proto_ops l2cap_sock_ops = {
> .recvmsg = l2cap_sock_recvmsg,
> .poll = bt_sock_poll,
> .ioctl = bt_sock_ioctl,
> + .gettstamp = sock_gettstamp,
> .mmap = sock_no_mmap,
> .socketpair = sock_no_socketpair,
> .shutdown = l2cap_sock_shutdown,
> diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
> index b1f49fcc0478..90bb53aa4bee 100644
> --- a/net/bluetooth/rfcomm/sock.c
> +++ b/net/bluetooth/rfcomm/sock.c
> @@ -1039,6 +1039,7 @@ static const struct proto_ops rfcomm_sock_ops = {
> .setsockopt = rfcomm_sock_setsockopt,
> .getsockopt = rfcomm_sock_getsockopt,
> .ioctl = rfcomm_sock_ioctl,
> + .gettstamp = sock_gettstamp,
> .poll = bt_sock_poll,
> .socketpair = sock_no_socketpair,
> .mmap = sock_no_mmap
> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
> index 9a580999ca57..d894406a5c3b 100644
> --- a/net/bluetooth/sco.c
> +++ b/net/bluetooth/sco.c
> @@ -1190,6 +1190,7 @@ static const struct proto_ops sco_sock_ops = {
> .recvmsg = sco_sock_recvmsg,
> .poll = bt_sock_poll,
> .ioctl = bt_sock_ioctl,
> + .gettstamp = sock_gettstamp,
> .mmap = sock_no_mmap,
> .socketpair = sock_no_socketpair,
> .shutdown = sco_sock_shutdown,
> diff --git a/net/can/af_can.c b/net/can/af_can.c
> index 1684ba5b51eb..e8fd5dc1780a 100644
> --- a/net/can/af_can.c
> +++ b/net/can/af_can.c
> @@ -89,13 +89,7 @@ static atomic_t skbcounter = ATOMIC_INIT(0);
>
> int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> {
> - struct sock *sk = sock->sk;
> -
> switch (cmd) {
> -
> - case SIOCGSTAMP:
> - return sock_get_timestamp(sk, (struct timeval __user *)arg);
> -
> default:
> return -ENOIOCTLCMD;
> }
> diff --git a/net/can/bcm.c b/net/can/bcm.c
> index 79bb8afa9c0c..a34ee52f19ea 100644
> --- a/net/can/bcm.c
> +++ b/net/can/bcm.c
> @@ -1689,6 +1689,7 @@ static const struct proto_ops bcm_ops = {
> .getname = sock_no_getname,
> .poll = datagram_poll,
> .ioctl = can_ioctl, /* use can_ioctl() from af_can.c */
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = sock_no_setsockopt,
> diff --git a/net/can/raw.c b/net/can/raw.c
> index c70207537488..afcbff063a67 100644
> --- a/net/can/raw.c
> +++ b/net/can/raw.c
> @@ -846,6 +846,7 @@ static const struct proto_ops raw_ops = {
> .getname = raw_getname,
> .poll = datagram_poll,
> .ioctl = can_ioctl, /* use can_ioctl() from af_can.c */
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = raw_setsockopt,
> diff --git a/net/compat.c b/net/compat.c
> index eeea5eb71639..a031bd333092 100644
> --- a/net/compat.c
> +++ b/net/compat.c
> @@ -395,63 +395,6 @@ COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
> return __compat_sys_setsockopt(fd, level, optname, optval, optlen);
> }
>
> -int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
> -{
> - struct compat_timeval __user *ctv;
> - int err;
> - struct timeval tv;
> -
> - if (COMPAT_USE_64BIT_TIME)
> - return sock_get_timestamp(sk, userstamp);
> -
> - ctv = (struct compat_timeval __user *) userstamp;
> - err = -ENOENT;
> - sock_enable_timestamp(sk, SOCK_TIMESTAMP);
> - tv = ktime_to_timeval(sock_read_timestamp(sk));
> -
> - if (tv.tv_sec == -1)
> - return err;
> - if (tv.tv_sec == 0) {
> - ktime_t kt = ktime_get_real();
> - sock_write_timestamp(sk, kt);
> - tv = ktime_to_timeval(kt);
> - }
> - err = 0;
> - if (put_user(tv.tv_sec, &ctv->tv_sec) ||
> - put_user(tv.tv_usec, &ctv->tv_usec))
> - err = -EFAULT;
> - return err;
> -}
> -EXPORT_SYMBOL(compat_sock_get_timestamp);
> -
> -int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
> -{
> - struct compat_timespec __user *ctv;
> - int err;
> - struct timespec ts;
> -
> - if (COMPAT_USE_64BIT_TIME)
> - return sock_get_timestampns (sk, userstamp);
> -
> - ctv = (struct compat_timespec __user *) userstamp;
> - err = -ENOENT;
> - sock_enable_timestamp(sk, SOCK_TIMESTAMP);
> - ts = ktime_to_timespec(sock_read_timestamp(sk));
> - if (ts.tv_sec == -1)
> - return err;
> - if (ts.tv_sec == 0) {
> - ktime_t kt = ktime_get_real();
> - sock_write_timestamp(sk, kt);
> - ts = ktime_to_timespec(kt);
> - }
> - err = 0;
> - if (put_user(ts.tv_sec, &ctv->tv_sec) ||
> - put_user(ts.tv_nsec, &ctv->tv_nsec))
> - err = -EFAULT;
> - return err;
> -}
> -EXPORT_SYMBOL(compat_sock_get_timestampns);
> -
> static int __compat_sys_getsockopt(int fd, int level, int optname,
> char __user *optval,
> int __user *optlen)
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 782343bb925b..dc7c31d66200 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -2977,39 +2977,44 @@ bool lock_sock_fast(struct sock *sk)
> }
> EXPORT_SYMBOL(lock_sock_fast);
>
> -int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
> +int sock_gettstamp(struct socket *sock, void __user *userstamp,
> + bool timeval, bool time32)
> {
> - struct timeval tv;
> + struct sock *sk = sock->sk;
> + struct timespec64 ts;
>
> sock_enable_timestamp(sk, SOCK_TIMESTAMP);
> - tv = ktime_to_timeval(sock_read_timestamp(sk));
> - if (tv.tv_sec == -1)
> + ts = ktime_to_timespec64(sk->sk_stamp);
> + if (ts.tv_sec == -1)
> return -ENOENT;
> - if (tv.tv_sec == 0) {
> + if (ts.tv_sec == 0) {
> ktime_t kt = ktime_get_real();
> - sock_write_timestamp(sk, kt);
> - tv = ktime_to_timeval(kt);
> + sock_write_timestamp(sk, kt);;
> + ts = ktime_to_timespec64(kt);
> }
> - return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
> -}
> -EXPORT_SYMBOL(sock_get_timestamp);
>
> -int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
> -{
> - struct timespec ts;
> + if (timeval)
> + ts.tv_nsec /= 1000;
>
> - sock_enable_timestamp(sk, SOCK_TIMESTAMP);
> - ts = ktime_to_timespec(sock_read_timestamp(sk));
> - if (ts.tv_sec == -1)
> - return -ENOENT;
> - if (ts.tv_sec == 0) {
> - ktime_t kt = ktime_get_real();
> - sock_write_timestamp(sk, kt);
> - ts = ktime_to_timespec(sk->sk_stamp);
> +#ifdef CONFIG_COMPAT_32BIT_TIME
> + if (time32)
> + return put_old_timespec32(&ts, userstamp);
> +#endif
> +#ifdef CONFIG_SPARC64
> + /* beware of padding in sparc64 timeval */
> + if (timeval && !in_compat_syscall()) {
> + struct __kernel_old_timeval __user tv = {
> + .tv_sec = ts.tv_sec;
> + .tv_usec = ts.tv_nsec;
> + };
> + if (copy_to_user(userstamp, &tv, sizeof(tv))
> + return -EFAULT;
> + return 0;
> }
> - return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
> +#endif
> + return put_timespec64(&ts, userstamp);
> }
> -EXPORT_SYMBOL(sock_get_timestampns);
> +EXPORT_SYMBOL(sock_gettstamp);
>
> void sock_enable_timestamp(struct sock *sk, int flag)
> {
> diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
> index 26a21d97b6b0..004535e4c070 100644
> --- a/net/dccp/ipv4.c
> +++ b/net/dccp/ipv4.c
> @@ -991,6 +991,7 @@ static const struct proto_ops inet_dccp_ops = {
> /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
> .poll = dccp_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> /* FIXME: work on inet_listen to rename it to sock_common_listen */
> .listen = inet_dccp_listen,
> .shutdown = inet_shutdown,
> diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
> index 57d84e9b7b6f..c4e4d1301062 100644
> --- a/net/dccp/ipv6.c
> +++ b/net/dccp/ipv6.c
> @@ -1075,6 +1075,7 @@ static const struct proto_ops inet6_dccp_ops = {
> .getname = inet6_getname,
> .poll = dccp_poll,
> .ioctl = inet6_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = inet_dccp_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
> index bc6b912603f1..ce2dfb997537 100644
> --- a/net/ieee802154/socket.c
> +++ b/net/ieee802154/socket.c
> @@ -164,10 +164,6 @@ static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
> struct sock *sk = sock->sk;
>
> switch (cmd) {
> - case SIOCGSTAMP:
> - return sock_get_timestamp(sk, (struct timeval __user *)arg);
> - case SIOCGSTAMPNS:
> - return sock_get_timestampns(sk, (struct timespec __user *)arg);
> case SIOCGIFADDR:
> case SIOCSIFADDR:
> return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
> @@ -426,6 +422,7 @@ static const struct proto_ops ieee802154_raw_ops = {
> .getname = sock_no_getname,
> .poll = datagram_poll,
> .ioctl = ieee802154_sock_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = sock_common_setsockopt,
> @@ -988,6 +985,7 @@ static const struct proto_ops ieee802154_dgram_ops = {
> .getname = sock_no_getname,
> .poll = datagram_poll,
> .ioctl = ieee802154_sock_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
> index eab3ebde981e..0f46d87715aa 100644
> --- a/net/ipv4/af_inet.c
> +++ b/net/ipv4/af_inet.c
> @@ -911,12 +911,6 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> struct rtentry rt;
>
> switch (cmd) {
> - case SIOCGSTAMP:
> - err = sock_get_timestamp(sk, (struct timeval __user *)arg);
> - break;
> - case SIOCGSTAMPNS:
> - err = sock_get_timestampns(sk, (struct timespec __user *)arg);
> - break;
> case SIOCADDRT:
> case SIOCDELRT:
> if (copy_from_user(&rt, p, sizeof(struct rtentry)))
> @@ -988,6 +982,7 @@ const struct proto_ops inet_stream_ops = {
> .getname = inet_getname,
> .poll = tcp_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = inet_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> @@ -1023,6 +1018,7 @@ const struct proto_ops inet_dgram_ops = {
> .getname = inet_getname,
> .poll = udp_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> @@ -1055,6 +1051,7 @@ static const struct proto_ops inet_sockraw_ops = {
> .getname = inet_getname,
> .poll = datagram_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> index 2f45d2a3e3a3..6d1133fd89f6 100644
> --- a/net/ipv6/af_inet6.c
> +++ b/net/ipv6/af_inet6.c
> @@ -546,12 +546,6 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> struct net *net = sock_net(sk);
>
> switch (cmd) {
> - case SIOCGSTAMP:
> - return sock_get_timestamp(sk, (struct timeval __user *)arg);
> -
> - case SIOCGSTAMPNS:
> - return sock_get_timestampns(sk, (struct timespec __user *)arg);
> -
> case SIOCADDRT:
> case SIOCDELRT:
>
> @@ -584,6 +578,7 @@ const struct proto_ops inet6_stream_ops = {
> .getname = inet6_getname,
> .poll = tcp_poll, /* ok */
> .ioctl = inet6_ioctl, /* must change */
> + .gettstamp = sock_gettstamp,
> .listen = inet_listen, /* ok */
> .shutdown = inet_shutdown, /* ok */
> .setsockopt = sock_common_setsockopt, /* ok */
> @@ -617,6 +612,7 @@ const struct proto_ops inet6_dgram_ops = {
> .getname = inet6_getname,
> .poll = udp_poll, /* ok */
> .ioctl = inet6_ioctl, /* must change */
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen, /* ok */
> .shutdown = inet_shutdown, /* ok */
> .setsockopt = sock_common_setsockopt, /* ok */
> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
> index 5a426226c762..84dbe21b71e5 100644
> --- a/net/ipv6/raw.c
> +++ b/net/ipv6/raw.c
> @@ -1356,6 +1356,7 @@ const struct proto_ops inet6_sockraw_ops = {
> .getname = inet6_getname,
> .poll = datagram_poll, /* ok */
> .ioctl = inet6_ioctl, /* must change */
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen, /* ok */
> .shutdown = inet_shutdown, /* ok */
> .setsockopt = sock_common_setsockopt, /* ok */
> diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
> index d4c60523c549..2cac910c1cd4 100644
> --- a/net/l2tp/l2tp_ip.c
> +++ b/net/l2tp/l2tp_ip.c
> @@ -618,6 +618,7 @@ static const struct proto_ops l2tp_ip_ops = {
> .getname = l2tp_ip_getname,
> .poll = datagram_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
> index 37a69df17cab..4ec546cc1dd6 100644
> --- a/net/l2tp/l2tp_ip6.c
> +++ b/net/l2tp/l2tp_ip6.c
> @@ -752,6 +752,7 @@ static const struct proto_ops l2tp_ip6_ops = {
> .getname = l2tp_ip6_getname,
> .poll = datagram_poll,
> .ioctl = inet6_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> index 1d3144d19903..4e97bbbf1916 100644
> --- a/net/netrom/af_netrom.c
> +++ b/net/netrom/af_netrom.c
> @@ -1199,7 +1199,6 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> {
> struct sock *sk = sock->sk;
> void __user *argp = (void __user *)arg;
> - int ret;
>
> switch (cmd) {
> case TIOCOUTQ: {
> @@ -1225,18 +1224,6 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> return put_user(amount, (int __user *)argp);
> }
>
> - case SIOCGSTAMP:
> - lock_sock(sk);
> - ret = sock_get_timestamp(sk, argp);
> - release_sock(sk);
> - return ret;
> -
> - case SIOCGSTAMPNS:
> - lock_sock(sk);
> - ret = sock_get_timestampns(sk, argp);
> - release_sock(sk);
> - return ret;
> -
> case SIOCGIFADDR:
> case SIOCSIFADDR:
> case SIOCGIFDSTADDR:
> @@ -1362,6 +1349,7 @@ static const struct proto_ops nr_proto_ops = {
> .getname = nr_getname,
> .poll = datagram_poll,
> .ioctl = nr_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = nr_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = nr_setsockopt,
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index 9419c5cf4de5..b012dc5ffb6e 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -4077,11 +4077,6 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
> spin_unlock_bh(&sk->sk_receive_queue.lock);
> return put_user(amount, (int __user *)arg);
> }
> - case SIOCGSTAMP:
> - return sock_get_timestamp(sk, (struct timeval __user *)arg);
> - case SIOCGSTAMPNS:
> - return sock_get_timestampns(sk, (struct timespec __user *)arg);
> -
> #ifdef CONFIG_INET
> case SIOCADDRT:
> case SIOCDELRT:
> @@ -4457,6 +4452,7 @@ static const struct proto_ops packet_ops_spkt = {
> .getname = packet_getname_spkt,
> .poll = datagram_poll,
> .ioctl = packet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = sock_no_setsockopt,
> @@ -4478,6 +4474,7 @@ static const struct proto_ops packet_ops = {
> .getname = packet_getname,
> .poll = packet_poll,
> .ioctl = packet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sock_no_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = packet_setsockopt,
> diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
> index b37e6e0a1026..7c5e8292cc0a 100644
> --- a/net/qrtr/qrtr.c
> +++ b/net/qrtr/qrtr.c
> @@ -968,9 +968,6 @@ static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> break;
> }
> break;
> - case SIOCGSTAMP:
> - rc = sock_get_timestamp(sk, argp);
> - break;
> case SIOCADDRT:
> case SIOCDELRT:
> case SIOCSIFADDR:
> @@ -1033,6 +1030,7 @@ static const struct proto_ops qrtr_proto_ops = {
> .recvmsg = qrtr_recvmsg,
> .getname = qrtr_getname,
> .ioctl = qrtr_ioctl,
> + .gettstamp = sock_gettstamp,
> .poll = datagram_poll,
> .shutdown = sock_no_shutdown,
> .setsockopt = sock_no_setsockopt,
> diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
> index c96f63ffe31e..e274bc6e1458 100644
> --- a/net/rose/af_rose.c
> +++ b/net/rose/af_rose.c
> @@ -1301,12 +1301,6 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> return put_user(amount, (unsigned int __user *) argp);
> }
>
> - case SIOCGSTAMP:
> - return sock_get_timestamp(sk, (struct timeval __user *) argp);
> -
> - case SIOCGSTAMPNS:
> - return sock_get_timestampns(sk, (struct timespec __user *) argp);
> -
> case SIOCGIFADDR:
> case SIOCSIFADDR:
> case SIOCGIFDSTADDR:
> @@ -1474,6 +1468,7 @@ static const struct proto_ops rose_proto_ops = {
> .getname = rose_getname,
> .poll = datagram_poll,
> .ioctl = rose_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = rose_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = rose_setsockopt,
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index 6200cd2b4b99..188c47eb206e 100644
> --- a/net/sctp/ipv6.c
> +++ b/net/sctp/ipv6.c
> @@ -1030,6 +1030,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
> .getname = sctp_getname,
> .poll = sctp_poll,
> .ioctl = inet6_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sctp_inet_listen,
> .shutdown = inet_shutdown,
> .setsockopt = sock_common_setsockopt,
> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> index 951afdeea5e9..f0631bf486b6 100644
> --- a/net/sctp/protocol.c
> +++ b/net/sctp/protocol.c
> @@ -1026,6 +1026,7 @@ static const struct proto_ops inet_seqpacket_ops = {
> .getname = inet_getname, /* Semantics are different. */
> .poll = sctp_poll,
> .ioctl = inet_ioctl,
> + .gettstamp = sock_gettstamp,
> .listen = sctp_inet_listen,
> .shutdown = inet_shutdown, /* Looks harmless. */
> .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */
> diff --git a/net/socket.c b/net/socket.c
> index 8255f5bda0aa..ab624d42ead5 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -1164,6 +1164,15 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
>
> err = open_related_ns(&net->ns, get_net_ns);
> break;
> + case SIOCGSTAMP:
> + case SIOCGSTAMPNS:
> + if (!sock->ops->gettstamp) {
> + err = -ENOIOCTLCMD;
> + break;
> + }
> + err = sock->ops->gettstamp(sock, argp,
> + cmd == SIOCGSTAMP, false);
> + break;
> default:
> err = sock_do_ioctl(net, sock, cmd, arg);
> break;
> @@ -2916,38 +2925,6 @@ void socket_seq_show(struct seq_file *seq)
> #endif /* CONFIG_PROC_FS */
>
> #ifdef CONFIG_COMPAT
> -static int do_siocgstamp(struct net *net, struct socket *sock,
> - unsigned int cmd, void __user *up)
> -{
> - mm_segment_t old_fs = get_fs();
> - struct timeval ktv;
> - int err;
> -
> - set_fs(KERNEL_DS);
> - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
> - set_fs(old_fs);
> - if (!err)
> - err = compat_put_timeval(&ktv, up);
> -
> - return err;
> -}
> -
> -static int do_siocgstampns(struct net *net, struct socket *sock,
> - unsigned int cmd, void __user *up)
> -{
> - mm_segment_t old_fs = get_fs();
> - struct timespec kts;
> - int err;
> -
> - set_fs(KERNEL_DS);
> - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
> - set_fs(old_fs);
> - if (!err)
> - err = compat_put_timespec(&kts, up);
> -
> - return err;
> -}
> -
> static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
> {
> struct compat_ifconf ifc32;
> @@ -3348,9 +3325,12 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
> case SIOCDELRT:
> return routing_ioctl(net, sock, cmd, argp);
> case SIOCGSTAMP:
> - return do_siocgstamp(net, sock, cmd, argp);
> case SIOCGSTAMPNS:
> - return do_siocgstampns(net, sock, cmd, argp);
> + if (!sock->ops->gettstamp)
> + return -ENOIOCTLCMD;
> + return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP,
> + !COMPAT_USE_64BIT_TIME);
> +
> case SIOCBONDSLAVEINFOQUERY:
> case SIOCBONDINFOQUERY:
> case SIOCSHWTSTAMP:
> diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
> index 20a511398389..0ea48a52ce79 100644
> --- a/net/x25/af_x25.c
> +++ b/net/x25/af_x25.c
> @@ -1398,18 +1398,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
> break;
> }
>
> - case SIOCGSTAMP:
> - rc = -EINVAL;
> - if (sk)
> - rc = sock_get_timestamp(sk,
> - (struct timeval __user *)argp);
> - break;
> - case SIOCGSTAMPNS:
> - rc = -EINVAL;
> - if (sk)
> - rc = sock_get_timestampns(sk,
> - (struct timespec __user *)argp);
> - break;
> case SIOCGIFADDR:
> case SIOCSIFADDR:
> case SIOCGIFDSTADDR:
> @@ -1681,8 +1669,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
> unsigned long arg)
> {
> void __user *argp = compat_ptr(arg);
> - struct sock *sk = sock->sk;
> -
> int rc = -ENOIOCTLCMD;
>
> switch(cmd) {
> @@ -1690,18 +1676,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
> case TIOCINQ:
> rc = x25_ioctl(sock, cmd, (unsigned long)argp);
> break;
> - case SIOCGSTAMP:
> - rc = -EINVAL;
> - if (sk)
> - rc = compat_sock_get_timestamp(sk,
> - (struct timeval __user*)argp);
> - break;
> - case SIOCGSTAMPNS:
> - rc = -EINVAL;
> - if (sk)
> - rc = compat_sock_get_timestampns(sk,
> - (struct timespec __user*)argp);
> - break;
> case SIOCGIFADDR:
> case SIOCSIFADDR:
> case SIOCGIFDSTADDR:
> @@ -1765,6 +1739,7 @@ static const struct proto_ops x25_proto_ops = {
> #ifdef CONFIG_COMPAT
> .compat_ioctl = compat_x25_ioctl,
> #endif
> + .gettstamp = sock_gettstamp,
> .listen = x25_listen,
> .shutdown = sock_no_shutdown,
> .setsockopt = x25_setsockopt,
> --
> 2.20.0
>
>
For the sctp bits
Acked-by: Neil Horman <[email protected]>


2019-04-17 10:01:00

by Marc Kleine-Budde

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On 4/16/19 10:32 PM, Arnd Bergmann wrote:
> The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
> socket protocol handlers, and all of those end up calling the same
> sock_get_timestamp()/sock_get_timestampns() helper functions, which
> results in a lot of duplicate code.
>
> With the introduction of 64-bit time_t on 32-bit architectures, this
> gets worse, as we then need four different ioctl commands in each
> socket protocol implementation.
>
> To simplify that, let's add a new .gettstamp() operation in
> struct proto_ops, and move ioctl implementation into the common
> sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
> through.
>
> We can reuse the sock_get_timestamp() implementation, but generalize
> it so it can deal with both native and compat mode, as well as
> timeval and timespec structures.
>
> Acked-by: Stefan Schmidt <[email protected]>
> Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
> Signed-off-by: Arnd Bergmann <[email protected]>

For the CAN part:

Acked-by: Marc Kleine-Budde <[email protected]>

regards,
Marc

--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |


Attachments:
signature.asc (488.00 B)
OpenPGP digital signature

2019-04-17 14:46:52

by Willem de Bruijn

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On Tue, Apr 16, 2019 at 4:38 PM Arnd Bergmann <[email protected]> wrote:
>
> The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
> socket protocol handlers, and all of those end up calling the same
> sock_get_timestamp()/sock_get_timestampns() helper functions, which
> results in a lot of duplicate code.
>
> With the introduction of 64-bit time_t on 32-bit architectures, this
> gets worse, as we then need four different ioctl commands in each
> socket protocol implementation.
>
> To simplify that, let's add a new .gettstamp() operation in
> struct proto_ops, and move ioctl implementation into the common
> sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
> through.
>
> We can reuse the sock_get_timestamp() implementation, but generalize
> it so it can deal with both native and compat mode, as well as
> timeval and timespec structures.
>
> Acked-by: Stefan Schmidt <[email protected]>
> Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> v2: reworked to not break sparc64 support

From the discussion of v1 I thought you planned to unconditionally
call sock_gettstamp() for all protocols, avoiding the need to plumb in
all these new callbacks?

That is more concise, though this closer to the existing behavior. So,
fine either way.

2019-04-17 16:19:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On Wed, Apr 17, 2019 at 4:46 PM Willem de Bruijn
<[email protected]> wrote:
> On Tue, Apr 16, 2019 at 4:38 PM Arnd Bergmann <[email protected]> wrote:
> > The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
> > socket protocol handlers, and all of those end up calling the same
> > sock_get_timestamp()/sock_get_timestampns() helper functions, which
> > results in a lot of duplicate code.
> >
> > With the introduction of 64-bit time_t on 32-bit architectures, this
> > gets worse, as we then need four different ioctl commands in each
> > socket protocol implementation.
> >
> > To simplify that, let's add a new .gettstamp() operation in
> > struct proto_ops, and move ioctl implementation into the common
> > sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
> > through.
> >
> > We can reuse the sock_get_timestamp() implementation, but generalize
> > it so it can deal with both native and compat mode, as well as
> > timeval and timespec structures.
> >
> > Acked-by: Stefan Schmidt <[email protected]>
> > Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
> > Signed-off-by: Arnd Bergmann <[email protected]>
> > ---
> > v2: reworked to not break sparc64 support
>
> From the discussion of v1 I thought you planned to unconditionally
> call sock_gettstamp() for all protocols, avoiding the need to plumb in
> all these new callbacks?
>
> That is more concise, though this closer to the existing behavior. So,
> fine either way.

Thanks for the reminder. I have definitely waited too long before revisiting
this series, and only had a vague recollection of that discussion but could
not find it in the logs (found it now, and the Link I quoted...).

I would prefer to get this series into the coming merge window, and
probably don't have time to rework it completely by then, so I hope
the current version is ok.

I also found your comment on lock_sock(), which could be easily
added inside of sock_gettstamp() if you think we should have that.
There is one more issue I just noticed (I dropped the necessary
sock_read_timestamp()), so I have to repost the series anyway
to fix that.

Arnd

2019-04-17 17:21:24

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

From: Neil Horman <[email protected]>
Date: Wed, 17 Apr 2019 05:35:23 -0400

> Acked-by: Neil Horman <[email protected]>

Neil, please quote appropriately in the future.

I have to scroll through all of those pages of quoted patch just to
see this one line.

Thank you.

2019-04-17 18:17:17

by Willem de Bruijn

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On Wed, Apr 17, 2019 at 12:19 PM Arnd Bergmann <[email protected]> wrote:
>
> On Wed, Apr 17, 2019 at 4:46 PM Willem de Bruijn
> <[email protected]> wrote:
> > On Tue, Apr 16, 2019 at 4:38 PM Arnd Bergmann <[email protected]> wrote:
> > > The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
> > > socket protocol handlers, and all of those end up calling the same
> > > sock_get_timestamp()/sock_get_timestampns() helper functions, which
> > > results in a lot of duplicate code.
> > >
> > > With the introduction of 64-bit time_t on 32-bit architectures, this
> > > gets worse, as we then need four different ioctl commands in each
> > > socket protocol implementation.
> > >
> > > To simplify that, let's add a new .gettstamp() operation in
> > > struct proto_ops, and move ioctl implementation into the common
> > > sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
> > > through.
> > >
> > > We can reuse the sock_get_timestamp() implementation, but generalize
> > > it so it can deal with both native and compat mode, as well as
> > > timeval and timespec structures.
> > >
> > > Acked-by: Stefan Schmidt <[email protected]>
> > > Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
> > > Signed-off-by: Arnd Bergmann <[email protected]>
> > > ---
> > > v2: reworked to not break sparc64 support
> >
> > From the discussion of v1 I thought you planned to unconditionally
> > call sock_gettstamp() for all protocols, avoiding the need to plumb in
> > all these new callbacks?
> >
> > That is more concise, though this closer to the existing behavior. So,
> > fine either way.
>
> Thanks for the reminder. I have definitely waited too long before revisiting
> this series, and only had a vague recollection of that discussion but could
> not find it in the logs (found it now, and the Link I quoted...).
>
> I would prefer to get this series into the coming merge window, and
> probably don't have time to rework it completely by then, so I hope
> the current version is ok.

Absolutely. This is a great simplification either way.

> I also found your comment on lock_sock(), which could be easily
> added inside of sock_gettstamp() if you think we should have that.

To remind, the issue is that sock_enable_timestamp should update both
sk_flags and net_enable_timestamp as one atomic operation, by holding
the socket lock. The lock is held when called from a setsockopt path.
And from some ioctl() implementations. The syzkaller reproducer
triggered through inet_release, so the most widely used paths are
buggy today.

Since the current state is inconsistent already, we can defer the fix.
I expect that it is now safe to add a lock around this logic without
triggering lockdep issues in any of the numerous paths. But just in
case, it still seems safer to do that in a separate patch that we can
revert or rework independent from this, if that would prove necessary.

> There is one more issue I just noticed (I dropped the necessary
> sock_read_timestamp()), so I have to repost the series anyway
> to fix that.

Instead of reading sk->sk_stamp directly? Yes, makes sense.

2019-04-17 20:16:43

by Neil Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 1/3] net: rework SIOCGSTAMP ioctl handling

On Wed, Apr 17, 2019 at 10:21:12AM -0700, David Miller wrote:
> From: Neil Horman <[email protected]>
> Date: Wed, 17 Apr 2019 05:35:23 -0400
>
> > Acked-by: Neil Horman <[email protected]>
>
> Neil, please quote appropriately in the future.
>
> I have to scroll through all of those pages of quoted patch just to
> see this one line.
>
> Thank you.
>
Sorry, completely forgot to snip. Will remember in the future
Neil