From 418a441604da6a79d0074bc2007e79d7f6f263e6 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 17 Oct 2023 11:15:40 -0700 Subject: [PATCH] kernel_setsockopt no longer available. We instead opt to use sock_setsockopt which is generally exactly the same and can be easily converted to map to kernel_setsockopt without impacting the code significantly. There are 3 methods we're calling with usec timeval's, and that is significantly different now that this requires a bit more compat code so we split these out to separate compat functions to handle them. Some of the TCP sock functions also have a slightly different signature that we want to split them out (struct socket vs. sock). Some further no longer return success, either. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 32 +++++++++++ kmod/src/kernelcompat.h | 101 +++++++++++++++++++++++++++++++++ kmod/src/net.c | 39 +++++-------- kmod/src/quorum.c | 9 +-- 4 files changed, 148 insertions(+), 33 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 61a74b8d..5c1eae89 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -330,3 +330,35 @@ endif ifneq (,$(shell grep 'ssize_t generic_perform_write.struct kiocb ., struct iov_iter' include/linux/fs.h)) ccflags-y += -DKC_GENERIC_PERFORM_WRITE_KIOCB_IOV_ITER endif + +# +# v5.7-rc6-2496-g76ee0785f42a +# +# net: add sock_set_sndtimeo +ifneq (,$(shell grep 'void sock_set_sndtimeo.struct sock' include/net/sock.h)) +ccflags-y += -DKC_SOCK_SET_SNDTIMEO +endif + +# +# v5.8-rc4-1931-gba423fdaa589 +# +# setsockopt functions are now passed a sockptr_t value instead of char* +ifneq (,$(shell grep -s 'include .linux/sockptr.h.' include/linux/net.h)) +ccflags-y += -DKC_SETSOCKOPT_SOCKPTR_T +endif + +# +# v5.7-rc6-2507-g71c48eb81c9e +# +# Adds a bunch of low level TCP sock parameter functions that we want to use. +ifneq (,$(shell grep 'int tcp_sock_set_keepintvl' include/linux/tcp.h)) +ccflags-y += -DKC_HAVE_TCP_SET_SOCKFN +endif + +# +# v4.16-rc3-13-ga84d1169164b +# +# Fixes y2038 issues with struct timeval. +ifneq (,$(shell grep -s '^struct __kernel_old_timeval .' include/uapi/linux/time_types.h)) +ccflags-y += -DKC_KERNEL_OLD_TIMEVAL_STRUCT +endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index b79e9ef4..6e4cdc02 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -333,4 +333,105 @@ static inline struct bio *kc_bio_alloc(struct block_device *bdev, unsigned short #define fiemap_prep(inode, fieinfo, start, len, flags) fiemap_check_flags(fieinfo, flags) #endif +#ifndef KC_KERNEL_OLD_TIMEVAL_STRUCT +#define __kernel_old_timeval timeval +#define ns_to_kernel_old_timeval(ktime) ns_to_timeval(ktime.tv64) +#endif + +#ifdef KC_SOCK_SET_SNDTIMEO +#include +static inline int kc_sock_set_sndtimeo(struct socket *sock, s64 secs) +{ + sock_set_sndtimeo(sock->sk, secs); + return 0; +} +static inline int kc_tcp_sock_set_rcvtimeo(struct socket *sock, ktime_t to) +{ + struct __kernel_old_timeval tv; + sockptr_t kopt; + + tv = ns_to_kernel_old_timeval(to); + + kopt = KERNEL_SOCKPTR(&tv); + + return sock_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO_NEW, + kopt, sizeof(tv)); +} +#else +#include +static inline int kc_sock_set_sndtimeo(struct socket *sock, s64 secs) +{ + struct timeval tv = { .tv_sec = secs, .tv_usec = 0 }; + return kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, + (char *)&tv, sizeof(tv)); +} +static inline int kc_tcp_sock_set_rcvtimeo(struct socket *sock, ktime_t to) +{ + struct __kernel_old_timeval tv; + + tv = ns_to_kernel_old_timeval(to); + return kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, + (char *)&tv, sizeof(tv)); +} +#endif + +#ifdef KC_SETSOCKOPT_SOCKPTR_T +static inline int kc_sock_setsockopt(struct socket *sock, int level, int op, int *optval, unsigned int optlen) +{ + sockptr_t kopt = KERNEL_SOCKPTR(optval); + return sock_setsockopt(sock, level, op, kopt, sizeof(optval)); +} +#else +static inline int kc_sock_setsockopt(struct socket *sock, int level, int op, int *optval, unsigned int optlen) +{ + return kernel_setsockopt(sock, level, op, (char *)optval, sizeof(optval)); +} +#endif + +#ifdef KC_HAVE_TCP_SET_SOCKFN +#include +#include +static inline int kc_tcp_sock_set_keepintvl(struct socket *sock, int val) +{ + return tcp_sock_set_keepintvl(sock->sk, val); +} +static inline int kc_tcp_sock_set_keepidle(struct socket *sock, int val) +{ + return tcp_sock_set_keepidle(sock->sk, val); +} +static inline int kc_tcp_sock_set_user_timeout(struct socket *sock, int val) +{ + tcp_sock_set_user_timeout(sock->sk, val); + return 0; +} +static inline int kc_tcp_sock_set_nodelay(struct socket *sock) +{ + tcp_sock_set_nodelay(sock->sk); + return 0; +} +#else +#include +#include +static inline int kc_tcp_sock_set_keepintvl(struct socket *sock, int val) +{ + int optval = val; + return kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, (char *)&optval, sizeof(optval)); +} +static inline int kc_tcp_sock_set_keepidle(struct socket *sock, int val) +{ + int optval = val; + return kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (char *)&optval, sizeof(optval)); +} +static inline int kc_tcp_sock_set_user_timeout(struct socket *sock, int val) +{ + int optval = val; + return kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, (char *)&optval, sizeof(optval)); +} +static inline int kc_tcp_sock_set_nodelay(struct socket *sock) +{ + int optval = 1; + return kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&optval, sizeof(optval)); +} +#endif + #endif diff --git a/kmod/src/net.c b/kmod/src/net.c index bbcff7db..d7c68743 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -904,53 +904,44 @@ static void destroy_conn(struct scoutfs_net_connection *conn) static int sock_opts_and_names(struct scoutfs_net_connection *conn, struct socket *sock) { - struct timeval tv; int optval; int ret; /* we use a keepalive timeout instead of send timeout */ - tv.tv_sec = 0; - tv.tv_usec = 0; - ret = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - (char *)&tv, sizeof(tv)); + ret = kc_sock_set_sndtimeo(sock, 0); if (ret) goto out; /* not checked when user_timeout != 0, but for clarity */ optval = UNRESPONSIVE_PROBES; - ret = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT, - (char *)&optval, sizeof(optval)); + ret = kc_sock_setsockopt(sock, SOL_TCP, TCP_KEEPCNT, + &optval, sizeof(optval)); if (ret) goto out; BUILD_BUG_ON(UNRESPONSIVE_PROBES >= UNRESPONSIVE_TIMEOUT_SECS); optval = UNRESPONSIVE_TIMEOUT_SECS - (UNRESPONSIVE_PROBES); - ret = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, - (char *)&optval, sizeof(optval)); + ret = kc_tcp_sock_set_keepidle(sock, optval); if (ret) goto out; optval = 1; - ret = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, - (char *)&optval, sizeof(optval)); + ret = kc_tcp_sock_set_keepintvl(sock, optval); if (ret) goto out; optval = UNRESPONSIVE_TIMEOUT_SECS * MSEC_PER_SEC; - ret = kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, - (char *)&optval, sizeof(optval)); + ret = kc_tcp_sock_set_user_timeout(sock, optval); if (ret) goto out; optval = 1; - ret = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (char *)&optval, sizeof(optval)); + ret = kc_sock_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + &optval, sizeof(optval)); if (ret) goto out; - optval = 1; - ret = kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, - (char *)&optval, sizeof(optval)); + ret = kc_tcp_sock_set_nodelay(sock); if (ret) goto out; @@ -1049,7 +1040,6 @@ static void scoutfs_net_connect_worker(struct work_struct *work) DEFINE_CONN_FROM_WORK(conn, work, connect_work); struct super_block *sb = conn->sb; struct socket *sock; - struct timeval tv; int ret; trace_scoutfs_net_connect_work_enter(sb, 0, 0); @@ -1060,11 +1050,8 @@ static void scoutfs_net_connect_worker(struct work_struct *work) sock->sk->sk_allocation = GFP_NOFS; - /* caller specified connect timeout */ - tv.tv_sec = conn->connect_timeout_ms / MSEC_PER_SEC; - tv.tv_usec = (conn->connect_timeout_ms % MSEC_PER_SEC) * USEC_PER_MSEC; - ret = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - (char *)&tv, sizeof(tv)); + /* caller specified connect timeout, defaults to 1 sec */ + ret = kc_sock_set_sndtimeo(sock, conn->connect_timeout_ms / MSEC_PER_SEC); if (ret) { sock_release(sock); goto out; @@ -1462,8 +1449,8 @@ int scoutfs_net_bind(struct super_block *sb, sock->sk->sk_allocation = GFP_NOFS; optval = 1; - ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&optval, sizeof(optval)); + ret = kc_sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + &optval, sizeof(optval)); if (ret) goto out; diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index ede23494..7308b1dc 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -303,7 +303,6 @@ static int recv_msg(struct super_block *sb, struct quorum_host_msg *msg, DECLARE_QUORUM_INFO(sb, qinf); struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct scoutfs_quorum_message qmes; - struct timeval tv; ktime_t rel_to; ktime_t now; int ret; @@ -328,14 +327,10 @@ static int recv_msg(struct super_block *sb, struct quorum_host_msg *msg, else rel_to = ns_to_ktime(0); - tv = ktime_to_timeval(rel_to); - if (tv.tv_sec == 0 && tv.tv_usec == 0) { + if (ktime_compare(rel_to, ns_to_ktime(NSEC_PER_USEC)) <= 0) { mh.msg_flags |= MSG_DONTWAIT; } else { - ret = kernel_setsockopt(qinf->sock, SOL_SOCKET, SO_RCVTIMEO, - (char *)&tv, sizeof(tv)); - if (ret < 0) - return ret; + ret = kc_tcp_sock_set_rcvtimeo(qinf->sock, rel_to); } #ifdef KC_MSGHDR_STRUCT_IOV_ITER