162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/net/sunrpc/xprtsock.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Client-side transport implementation for sockets. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * TCP callback races fixes (C) 1998 Red Hat 862306a36Sopenharmony_ci * TCP send fixes (C) 1998 Red Hat 962306a36Sopenharmony_ci * TCP NFS related read + write fixes 1062306a36Sopenharmony_ci * (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Rewrite of larges part of the code in order to stabilize TCP stuff. 1362306a36Sopenharmony_ci * Fix behaviour when socket buffer is full. 1462306a36Sopenharmony_ci * (C) 1999 Trond Myklebust <trond.myklebust@fys.uio.no> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * IP socket transport implementation, (C) 2005 Chuck Lever <cel@netapp.com> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005. 1962306a36Sopenharmony_ci * <gilles.quillard@bull.net> 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/string.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/capability.h> 2762306a36Sopenharmony_ci#include <linux/pagemap.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/socket.h> 3062306a36Sopenharmony_ci#include <linux/in.h> 3162306a36Sopenharmony_ci#include <linux/net.h> 3262306a36Sopenharmony_ci#include <linux/mm.h> 3362306a36Sopenharmony_ci#include <linux/un.h> 3462306a36Sopenharmony_ci#include <linux/udp.h> 3562306a36Sopenharmony_ci#include <linux/tcp.h> 3662306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 3762306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 3862306a36Sopenharmony_ci#include <linux/sunrpc/sched.h> 3962306a36Sopenharmony_ci#include <linux/sunrpc/svcsock.h> 4062306a36Sopenharmony_ci#include <linux/sunrpc/xprtsock.h> 4162306a36Sopenharmony_ci#include <linux/file.h> 4262306a36Sopenharmony_ci#ifdef CONFIG_SUNRPC_BACKCHANNEL 4362306a36Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h> 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <net/sock.h> 4762306a36Sopenharmony_ci#include <net/checksum.h> 4862306a36Sopenharmony_ci#include <net/udp.h> 4962306a36Sopenharmony_ci#include <net/tcp.h> 5062306a36Sopenharmony_ci#include <net/tls_prot.h> 5162306a36Sopenharmony_ci#include <net/handshake.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include <linux/bvec.h> 5462306a36Sopenharmony_ci#include <linux/highmem.h> 5562306a36Sopenharmony_ci#include <linux/uio.h> 5662306a36Sopenharmony_ci#include <linux/sched/mm.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include <trace/events/sock.h> 5962306a36Sopenharmony_ci#include <trace/events/sunrpc.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#include "socklib.h" 6262306a36Sopenharmony_ci#include "sunrpc.h" 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void xs_close(struct rpc_xprt *xprt); 6562306a36Sopenharmony_cistatic void xs_set_srcport(struct sock_xprt *transport, struct socket *sock); 6662306a36Sopenharmony_cistatic void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, 6762306a36Sopenharmony_ci struct socket *sock); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * xprtsock tunables 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistatic unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; 7362306a36Sopenharmony_cistatic unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; 7462306a36Sopenharmony_cistatic unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; 7762306a36Sopenharmony_cistatic unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define XS_TCP_LINGER_TO (15U * HZ) 8062306a36Sopenharmony_cistatic unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * We can register our own files under /proc/sys/sunrpc by 8462306a36Sopenharmony_ci * calling register_sysctl() again. The files in that 8562306a36Sopenharmony_ci * directory become the union of all files registered there. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * We simply need to make sure that we don't collide with 8862306a36Sopenharmony_ci * someone else's file names! 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; 9262306a36Sopenharmony_cistatic unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; 9362306a36Sopenharmony_cistatic unsigned int max_tcp_slot_table_limit = RPC_MAX_SLOT_TABLE_LIMIT; 9462306a36Sopenharmony_cistatic unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; 9562306a36Sopenharmony_cistatic unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct ctl_table_header *sunrpc_table_header; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic struct xprt_class xs_local_transport; 10062306a36Sopenharmony_cistatic struct xprt_class xs_udp_transport; 10162306a36Sopenharmony_cistatic struct xprt_class xs_tcp_transport; 10262306a36Sopenharmony_cistatic struct xprt_class xs_tcp_tls_transport; 10362306a36Sopenharmony_cistatic struct xprt_class xs_bc_tcp_transport; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * FIXME: changing the UDP slot table size should also resize the UDP 10762306a36Sopenharmony_ci * socket buffers for existing UDP transports 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic struct ctl_table xs_tunables_table[] = { 11062306a36Sopenharmony_ci { 11162306a36Sopenharmony_ci .procname = "udp_slot_table_entries", 11262306a36Sopenharmony_ci .data = &xprt_udp_slot_table_entries, 11362306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 11462306a36Sopenharmony_ci .mode = 0644, 11562306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 11662306a36Sopenharmony_ci .extra1 = &min_slot_table_size, 11762306a36Sopenharmony_ci .extra2 = &max_slot_table_size 11862306a36Sopenharmony_ci }, 11962306a36Sopenharmony_ci { 12062306a36Sopenharmony_ci .procname = "tcp_slot_table_entries", 12162306a36Sopenharmony_ci .data = &xprt_tcp_slot_table_entries, 12262306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 12362306a36Sopenharmony_ci .mode = 0644, 12462306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 12562306a36Sopenharmony_ci .extra1 = &min_slot_table_size, 12662306a36Sopenharmony_ci .extra2 = &max_slot_table_size 12762306a36Sopenharmony_ci }, 12862306a36Sopenharmony_ci { 12962306a36Sopenharmony_ci .procname = "tcp_max_slot_table_entries", 13062306a36Sopenharmony_ci .data = &xprt_max_tcp_slot_table_entries, 13162306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 13262306a36Sopenharmony_ci .mode = 0644, 13362306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 13462306a36Sopenharmony_ci .extra1 = &min_slot_table_size, 13562306a36Sopenharmony_ci .extra2 = &max_tcp_slot_table_limit 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci { 13862306a36Sopenharmony_ci .procname = "min_resvport", 13962306a36Sopenharmony_ci .data = &xprt_min_resvport, 14062306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 14162306a36Sopenharmony_ci .mode = 0644, 14262306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 14362306a36Sopenharmony_ci .extra1 = &xprt_min_resvport_limit, 14462306a36Sopenharmony_ci .extra2 = &xprt_max_resvport_limit 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci { 14762306a36Sopenharmony_ci .procname = "max_resvport", 14862306a36Sopenharmony_ci .data = &xprt_max_resvport, 14962306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 15062306a36Sopenharmony_ci .mode = 0644, 15162306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 15262306a36Sopenharmony_ci .extra1 = &xprt_min_resvport_limit, 15362306a36Sopenharmony_ci .extra2 = &xprt_max_resvport_limit 15462306a36Sopenharmony_ci }, 15562306a36Sopenharmony_ci { 15662306a36Sopenharmony_ci .procname = "tcp_fin_timeout", 15762306a36Sopenharmony_ci .data = &xs_tcp_fin_timeout, 15862306a36Sopenharmony_ci .maxlen = sizeof(xs_tcp_fin_timeout), 15962306a36Sopenharmony_ci .mode = 0644, 16062306a36Sopenharmony_ci .proc_handler = proc_dointvec_jiffies, 16162306a36Sopenharmony_ci }, 16262306a36Sopenharmony_ci { }, 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * Wait duration for a reply from the RPC portmapper. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci#define XS_BIND_TO (60U * HZ) 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * Delay if a UDP socket connect error occurs. This is most likely some 17262306a36Sopenharmony_ci * kind of resource problem on the local host. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci#define XS_UDP_REEST_TO (2U * HZ) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * The reestablish timeout allows clients to delay for a bit before attempting 17862306a36Sopenharmony_ci * to reconnect to a server that just dropped our connection. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * We implement an exponential backoff when trying to reestablish a TCP 18162306a36Sopenharmony_ci * transport connection with the server. Some servers like to drop a TCP 18262306a36Sopenharmony_ci * connection when they are overworked, so we start with a short timeout and 18362306a36Sopenharmony_ci * increase over time if the server is down or not responding. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci#define XS_TCP_INIT_REEST_TO (3U * HZ) 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * TCP idle timeout; client drops the transport socket if it is idle 18962306a36Sopenharmony_ci * for this long. Note that we also timeout UDP sockets to prevent 19062306a36Sopenharmony_ci * holding port numbers when there is no RPC traffic. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci#define XS_IDLE_DISC_TO (5U * 60 * HZ) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * TLS handshake timeout. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci#define XS_TLS_HANDSHAKE_TO (10U * HZ) 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 20062306a36Sopenharmony_ci# undef RPC_DEBUG_DATA 20162306a36Sopenharmony_ci# define RPCDBG_FACILITY RPCDBG_TRANS 20262306a36Sopenharmony_ci#endif 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci#ifdef RPC_DEBUG_DATA 20562306a36Sopenharmony_cistatic void xs_pktdump(char *msg, u32 *packet, unsigned int count) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci u8 *buf = (u8 *) packet; 20862306a36Sopenharmony_ci int j; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci dprintk("RPC: %s\n", msg); 21162306a36Sopenharmony_ci for (j = 0; j < count && j < 128; j += 4) { 21262306a36Sopenharmony_ci if (!(j & 31)) { 21362306a36Sopenharmony_ci if (j) 21462306a36Sopenharmony_ci dprintk("\n"); 21562306a36Sopenharmony_ci dprintk("0x%04x ", j); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci dprintk("%02x%02x%02x%02x ", 21862306a36Sopenharmony_ci buf[j], buf[j+1], buf[j+2], buf[j+3]); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci dprintk("\n"); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci#else 22362306a36Sopenharmony_cistatic inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci /* NOP */ 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci#endif 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline struct rpc_xprt *xprt_from_sock(struct sock *sk) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return (struct rpc_xprt *) sk->sk_user_data; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return (struct sockaddr *) &xprt->addr; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic inline struct sockaddr_un *xs_addr_un(struct rpc_xprt *xprt) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return (struct sockaddr_un *) &xprt->addr; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci return (struct sockaddr_in *) &xprt->addr; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return (struct sockaddr_in6 *) &xprt->addr; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void xs_format_common_peer_addresses(struct rpc_xprt *xprt) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct sockaddr *sap = xs_addr(xprt); 25762306a36Sopenharmony_ci struct sockaddr_in6 *sin6; 25862306a36Sopenharmony_ci struct sockaddr_in *sin; 25962306a36Sopenharmony_ci struct sockaddr_un *sun; 26062306a36Sopenharmony_ci char buf[128]; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci switch (sap->sa_family) { 26362306a36Sopenharmony_ci case AF_LOCAL: 26462306a36Sopenharmony_ci sun = xs_addr_un(xprt); 26562306a36Sopenharmony_ci if (sun->sun_path[0]) { 26662306a36Sopenharmony_ci strscpy(buf, sun->sun_path, sizeof(buf)); 26762306a36Sopenharmony_ci } else { 26862306a36Sopenharmony_ci buf[0] = '@'; 26962306a36Sopenharmony_ci strscpy(buf+1, sun->sun_path+1, sizeof(buf)-1); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR] = 27262306a36Sopenharmony_ci kstrdup(buf, GFP_KERNEL); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci case AF_INET: 27562306a36Sopenharmony_ci (void)rpc_ntop(sap, buf, sizeof(buf)); 27662306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR] = 27762306a36Sopenharmony_ci kstrdup(buf, GFP_KERNEL); 27862306a36Sopenharmony_ci sin = xs_addr_in(xprt); 27962306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr)); 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci case AF_INET6: 28262306a36Sopenharmony_ci (void)rpc_ntop(sap, buf, sizeof(buf)); 28362306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR] = 28462306a36Sopenharmony_ci kstrdup(buf, GFP_KERNEL); 28562306a36Sopenharmony_ci sin6 = xs_addr_in6(xprt); 28662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci default: 28962306a36Sopenharmony_ci BUG(); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic void xs_format_common_peer_ports(struct rpc_xprt *xprt) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct sockaddr *sap = xs_addr(xprt); 29862306a36Sopenharmony_ci char buf[128]; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap)); 30162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap)); 30462306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void xs_format_peer_addresses(struct rpc_xprt *xprt, 30862306a36Sopenharmony_ci const char *protocol, 30962306a36Sopenharmony_ci const char *netid) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; 31262306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_NETID] = netid; 31362306a36Sopenharmony_ci xs_format_common_peer_addresses(xprt); 31462306a36Sopenharmony_ci xs_format_common_peer_ports(xprt); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void xs_update_peer_port(struct rpc_xprt *xprt) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]); 32062306a36Sopenharmony_ci kfree(xprt->address_strings[RPC_DISPLAY_PORT]); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci xs_format_common_peer_ports(xprt); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void xs_free_peer_addresses(struct rpc_xprt *xprt) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci unsigned int i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci for (i = 0; i < RPC_DISPLAY_MAX; i++) 33062306a36Sopenharmony_ci switch (i) { 33162306a36Sopenharmony_ci case RPC_DISPLAY_PROTO: 33262306a36Sopenharmony_ci case RPC_DISPLAY_NETID: 33362306a36Sopenharmony_ci continue; 33462306a36Sopenharmony_ci default: 33562306a36Sopenharmony_ci kfree(xprt->address_strings[i]); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic size_t 34062306a36Sopenharmony_cixs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci size_t i,n; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!want || !(buf->flags & XDRBUF_SPARSE_PAGES)) 34562306a36Sopenharmony_ci return want; 34662306a36Sopenharmony_ci n = (buf->page_base + want + PAGE_SIZE - 1) >> PAGE_SHIFT; 34762306a36Sopenharmony_ci for (i = 0; i < n; i++) { 34862306a36Sopenharmony_ci if (buf->pages[i]) 34962306a36Sopenharmony_ci continue; 35062306a36Sopenharmony_ci buf->bvec[i].bv_page = buf->pages[i] = alloc_page(gfp); 35162306a36Sopenharmony_ci if (!buf->pages[i]) { 35262306a36Sopenharmony_ci i *= PAGE_SIZE; 35362306a36Sopenharmony_ci return i > buf->page_base ? i - buf->page_base : 0; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci return want; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int 36062306a36Sopenharmony_cixs_sock_process_cmsg(struct socket *sock, struct msghdr *msg, 36162306a36Sopenharmony_ci struct cmsghdr *cmsg, int ret) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci u8 content_type = tls_get_record_type(sock->sk, cmsg); 36462306a36Sopenharmony_ci u8 level, description; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci switch (content_type) { 36762306a36Sopenharmony_ci case 0: 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case TLS_RECORD_TYPE_DATA: 37062306a36Sopenharmony_ci /* TLS sets EOR at the end of each application data 37162306a36Sopenharmony_ci * record, even though there might be more frames 37262306a36Sopenharmony_ci * waiting to be decrypted. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci msg->msg_flags &= ~MSG_EOR; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case TLS_RECORD_TYPE_ALERT: 37762306a36Sopenharmony_ci tls_alert_recv(sock->sk, msg, &level, &description); 37862306a36Sopenharmony_ci ret = (level == TLS_ALERT_LEVEL_FATAL) ? 37962306a36Sopenharmony_ci -EACCES : -EAGAIN; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci default: 38262306a36Sopenharmony_ci /* discard this record type */ 38362306a36Sopenharmony_ci ret = -EAGAIN; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci return ret; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int 38962306a36Sopenharmony_cixs_sock_recv_cmsg(struct socket *sock, struct msghdr *msg, int flags) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci union { 39262306a36Sopenharmony_ci struct cmsghdr cmsg; 39362306a36Sopenharmony_ci u8 buf[CMSG_SPACE(sizeof(u8))]; 39462306a36Sopenharmony_ci } u; 39562306a36Sopenharmony_ci int ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci msg->msg_control = &u; 39862306a36Sopenharmony_ci msg->msg_controllen = sizeof(u); 39962306a36Sopenharmony_ci ret = sock_recvmsg(sock, msg, flags); 40062306a36Sopenharmony_ci if (msg->msg_controllen != sizeof(u)) 40162306a36Sopenharmony_ci ret = xs_sock_process_cmsg(sock, msg, &u.cmsg, ret); 40262306a36Sopenharmony_ci return ret; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic ssize_t 40662306a36Sopenharmony_cixs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci ssize_t ret; 40962306a36Sopenharmony_ci if (seek != 0) 41062306a36Sopenharmony_ci iov_iter_advance(&msg->msg_iter, seek); 41162306a36Sopenharmony_ci ret = xs_sock_recv_cmsg(sock, msg, flags); 41262306a36Sopenharmony_ci return ret > 0 ? ret + seek : ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic ssize_t 41662306a36Sopenharmony_cixs_read_kvec(struct socket *sock, struct msghdr *msg, int flags, 41762306a36Sopenharmony_ci struct kvec *kvec, size_t count, size_t seek) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci iov_iter_kvec(&msg->msg_iter, ITER_DEST, kvec, 1, count); 42062306a36Sopenharmony_ci return xs_sock_recvmsg(sock, msg, flags, seek); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic ssize_t 42462306a36Sopenharmony_cixs_read_bvec(struct socket *sock, struct msghdr *msg, int flags, 42562306a36Sopenharmony_ci struct bio_vec *bvec, unsigned long nr, size_t count, 42662306a36Sopenharmony_ci size_t seek) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci iov_iter_bvec(&msg->msg_iter, ITER_DEST, bvec, nr, count); 42962306a36Sopenharmony_ci return xs_sock_recvmsg(sock, msg, flags, seek); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic ssize_t 43362306a36Sopenharmony_cixs_read_discard(struct socket *sock, struct msghdr *msg, int flags, 43462306a36Sopenharmony_ci size_t count) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci iov_iter_discard(&msg->msg_iter, ITER_DEST, count); 43762306a36Sopenharmony_ci return xs_sock_recv_cmsg(sock, msg, flags); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 44162306a36Sopenharmony_cistatic void 44262306a36Sopenharmony_cixs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct bvec_iter bi = { 44562306a36Sopenharmony_ci .bi_size = count, 44662306a36Sopenharmony_ci }; 44762306a36Sopenharmony_ci struct bio_vec bv; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci bvec_iter_advance(bvec, &bi, seek & PAGE_MASK); 45062306a36Sopenharmony_ci for_each_bvec(bv, bvec, bi, bi) 45162306a36Sopenharmony_ci flush_dcache_page(bv.bv_page); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci#else 45462306a36Sopenharmony_cistatic inline void 45562306a36Sopenharmony_cixs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci#endif 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic ssize_t 46162306a36Sopenharmony_cixs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, 46262306a36Sopenharmony_ci struct xdr_buf *buf, size_t count, size_t seek, size_t *read) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci size_t want, seek_init = seek, offset = 0; 46562306a36Sopenharmony_ci ssize_t ret; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci want = min_t(size_t, count, buf->head[0].iov_len); 46862306a36Sopenharmony_ci if (seek < want) { 46962306a36Sopenharmony_ci ret = xs_read_kvec(sock, msg, flags, &buf->head[0], want, seek); 47062306a36Sopenharmony_ci if (ret <= 0) 47162306a36Sopenharmony_ci goto sock_err; 47262306a36Sopenharmony_ci offset += ret; 47362306a36Sopenharmony_ci if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) 47462306a36Sopenharmony_ci goto out; 47562306a36Sopenharmony_ci if (ret != want) 47662306a36Sopenharmony_ci goto out; 47762306a36Sopenharmony_ci seek = 0; 47862306a36Sopenharmony_ci } else { 47962306a36Sopenharmony_ci seek -= want; 48062306a36Sopenharmony_ci offset += want; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci want = xs_alloc_sparse_pages( 48462306a36Sopenharmony_ci buf, min_t(size_t, count - offset, buf->page_len), 48562306a36Sopenharmony_ci GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); 48662306a36Sopenharmony_ci if (seek < want) { 48762306a36Sopenharmony_ci ret = xs_read_bvec(sock, msg, flags, buf->bvec, 48862306a36Sopenharmony_ci xdr_buf_pagecount(buf), 48962306a36Sopenharmony_ci want + buf->page_base, 49062306a36Sopenharmony_ci seek + buf->page_base); 49162306a36Sopenharmony_ci if (ret <= 0) 49262306a36Sopenharmony_ci goto sock_err; 49362306a36Sopenharmony_ci xs_flush_bvec(buf->bvec, ret, seek + buf->page_base); 49462306a36Sopenharmony_ci ret -= buf->page_base; 49562306a36Sopenharmony_ci offset += ret; 49662306a36Sopenharmony_ci if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) 49762306a36Sopenharmony_ci goto out; 49862306a36Sopenharmony_ci if (ret != want) 49962306a36Sopenharmony_ci goto out; 50062306a36Sopenharmony_ci seek = 0; 50162306a36Sopenharmony_ci } else { 50262306a36Sopenharmony_ci seek -= want; 50362306a36Sopenharmony_ci offset += want; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci want = min_t(size_t, count - offset, buf->tail[0].iov_len); 50762306a36Sopenharmony_ci if (seek < want) { 50862306a36Sopenharmony_ci ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek); 50962306a36Sopenharmony_ci if (ret <= 0) 51062306a36Sopenharmony_ci goto sock_err; 51162306a36Sopenharmony_ci offset += ret; 51262306a36Sopenharmony_ci if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci if (ret != want) 51562306a36Sopenharmony_ci goto out; 51662306a36Sopenharmony_ci } else if (offset < seek_init) 51762306a36Sopenharmony_ci offset = seek_init; 51862306a36Sopenharmony_ci ret = -EMSGSIZE; 51962306a36Sopenharmony_ciout: 52062306a36Sopenharmony_ci *read = offset - seek_init; 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_cisock_err: 52362306a36Sopenharmony_ci offset += seek; 52462306a36Sopenharmony_ci goto out; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void 52862306a36Sopenharmony_cixs_read_header(struct sock_xprt *transport, struct xdr_buf *buf) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci if (!transport->recv.copied) { 53162306a36Sopenharmony_ci if (buf->head[0].iov_len >= transport->recv.offset) 53262306a36Sopenharmony_ci memcpy(buf->head[0].iov_base, 53362306a36Sopenharmony_ci &transport->recv.xid, 53462306a36Sopenharmony_ci transport->recv.offset); 53562306a36Sopenharmony_ci transport->recv.copied = transport->recv.offset; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic bool 54062306a36Sopenharmony_cixs_read_stream_request_done(struct sock_xprt *transport) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return transport->recv.fraghdr & cpu_to_be32(RPC_LAST_STREAM_FRAGMENT); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic void 54662306a36Sopenharmony_cixs_read_stream_check_eor(struct sock_xprt *transport, 54762306a36Sopenharmony_ci struct msghdr *msg) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci if (xs_read_stream_request_done(transport)) 55062306a36Sopenharmony_ci msg->msg_flags |= MSG_EOR; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic ssize_t 55462306a36Sopenharmony_cixs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg, 55562306a36Sopenharmony_ci int flags, struct rpc_rqst *req) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct xdr_buf *buf = &req->rq_private_buf; 55862306a36Sopenharmony_ci size_t want, read; 55962306a36Sopenharmony_ci ssize_t ret; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci xs_read_header(transport, buf); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci want = transport->recv.len - transport->recv.offset; 56462306a36Sopenharmony_ci if (want != 0) { 56562306a36Sopenharmony_ci ret = xs_read_xdr_buf(transport->sock, msg, flags, buf, 56662306a36Sopenharmony_ci transport->recv.copied + want, 56762306a36Sopenharmony_ci transport->recv.copied, 56862306a36Sopenharmony_ci &read); 56962306a36Sopenharmony_ci transport->recv.offset += read; 57062306a36Sopenharmony_ci transport->recv.copied += read; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (transport->recv.offset == transport->recv.len) 57462306a36Sopenharmony_ci xs_read_stream_check_eor(transport, msg); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (want == 0) 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch (ret) { 58062306a36Sopenharmony_ci default: 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case -EFAULT: 58362306a36Sopenharmony_ci case -EMSGSIZE: 58462306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 58562306a36Sopenharmony_ci return read; 58662306a36Sopenharmony_ci case 0: 58762306a36Sopenharmony_ci return -ESHUTDOWN; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci return ret < 0 ? ret : read; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic size_t 59362306a36Sopenharmony_cixs_read_stream_headersize(bool isfrag) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci if (isfrag) 59662306a36Sopenharmony_ci return sizeof(__be32); 59762306a36Sopenharmony_ci return 3 * sizeof(__be32); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic ssize_t 60162306a36Sopenharmony_cixs_read_stream_header(struct sock_xprt *transport, struct msghdr *msg, 60262306a36Sopenharmony_ci int flags, size_t want, size_t seek) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct kvec kvec = { 60562306a36Sopenharmony_ci .iov_base = &transport->recv.fraghdr, 60662306a36Sopenharmony_ci .iov_len = want, 60762306a36Sopenharmony_ci }; 60862306a36Sopenharmony_ci return xs_read_kvec(transport->sock, msg, flags, &kvec, want, seek); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL) 61262306a36Sopenharmony_cistatic ssize_t 61362306a36Sopenharmony_cixs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 61662306a36Sopenharmony_ci struct rpc_rqst *req; 61762306a36Sopenharmony_ci ssize_t ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Is this transport associated with the backchannel? */ 62062306a36Sopenharmony_ci if (!xprt->bc_serv) 62162306a36Sopenharmony_ci return -ESHUTDOWN; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Look up and lock the request corresponding to the given XID */ 62462306a36Sopenharmony_ci req = xprt_lookup_bc_request(xprt, transport->recv.xid); 62562306a36Sopenharmony_ci if (!req) { 62662306a36Sopenharmony_ci printk(KERN_WARNING "Callback slot table overflowed\n"); 62762306a36Sopenharmony_ci return -ESHUTDOWN; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci if (transport->recv.copied && !req->rq_private_buf.len) 63062306a36Sopenharmony_ci return -ESHUTDOWN; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ret = xs_read_stream_request(transport, msg, flags, req); 63362306a36Sopenharmony_ci if (msg->msg_flags & (MSG_EOR|MSG_TRUNC)) 63462306a36Sopenharmony_ci xprt_complete_bc_request(req, transport->recv.copied); 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci req->rq_private_buf.len = transport->recv.copied; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci#else /* CONFIG_SUNRPC_BACKCHANNEL */ 64162306a36Sopenharmony_cistatic ssize_t 64262306a36Sopenharmony_cixs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci return -ESHUTDOWN; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic ssize_t 64962306a36Sopenharmony_cixs_read_stream_reply(struct sock_xprt *transport, struct msghdr *msg, int flags) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 65262306a36Sopenharmony_ci struct rpc_rqst *req; 65362306a36Sopenharmony_ci ssize_t ret = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* Look up and lock the request corresponding to the given XID */ 65662306a36Sopenharmony_ci spin_lock(&xprt->queue_lock); 65762306a36Sopenharmony_ci req = xprt_lookup_rqst(xprt, transport->recv.xid); 65862306a36Sopenharmony_ci if (!req || (transport->recv.copied && !req->rq_private_buf.len)) { 65962306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 66062306a36Sopenharmony_ci goto out; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci xprt_pin_rqst(req); 66362306a36Sopenharmony_ci spin_unlock(&xprt->queue_lock); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ret = xs_read_stream_request(transport, msg, flags, req); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci spin_lock(&xprt->queue_lock); 66862306a36Sopenharmony_ci if (msg->msg_flags & (MSG_EOR|MSG_TRUNC)) 66962306a36Sopenharmony_ci xprt_complete_rqst(req->rq_task, transport->recv.copied); 67062306a36Sopenharmony_ci else 67162306a36Sopenharmony_ci req->rq_private_buf.len = transport->recv.copied; 67262306a36Sopenharmony_ci xprt_unpin_rqst(req); 67362306a36Sopenharmony_ciout: 67462306a36Sopenharmony_ci spin_unlock(&xprt->queue_lock); 67562306a36Sopenharmony_ci return ret; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic ssize_t 67962306a36Sopenharmony_cixs_read_stream(struct sock_xprt *transport, int flags) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct msghdr msg = { 0 }; 68262306a36Sopenharmony_ci size_t want, read = 0; 68362306a36Sopenharmony_ci ssize_t ret = 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (transport->recv.len == 0) { 68662306a36Sopenharmony_ci want = xs_read_stream_headersize(transport->recv.copied != 0); 68762306a36Sopenharmony_ci ret = xs_read_stream_header(transport, &msg, flags, want, 68862306a36Sopenharmony_ci transport->recv.offset); 68962306a36Sopenharmony_ci if (ret <= 0) 69062306a36Sopenharmony_ci goto out_err; 69162306a36Sopenharmony_ci transport->recv.offset = ret; 69262306a36Sopenharmony_ci if (transport->recv.offset != want) 69362306a36Sopenharmony_ci return transport->recv.offset; 69462306a36Sopenharmony_ci transport->recv.len = be32_to_cpu(transport->recv.fraghdr) & 69562306a36Sopenharmony_ci RPC_FRAGMENT_SIZE_MASK; 69662306a36Sopenharmony_ci transport->recv.offset -= sizeof(transport->recv.fraghdr); 69762306a36Sopenharmony_ci read = ret; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci switch (be32_to_cpu(transport->recv.calldir)) { 70162306a36Sopenharmony_ci default: 70262306a36Sopenharmony_ci msg.msg_flags |= MSG_TRUNC; 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci case RPC_CALL: 70562306a36Sopenharmony_ci ret = xs_read_stream_call(transport, &msg, flags); 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case RPC_REPLY: 70862306a36Sopenharmony_ci ret = xs_read_stream_reply(transport, &msg, flags); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci if (msg.msg_flags & MSG_TRUNC) { 71162306a36Sopenharmony_ci transport->recv.calldir = cpu_to_be32(-1); 71262306a36Sopenharmony_ci transport->recv.copied = -1; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci if (ret < 0) 71562306a36Sopenharmony_ci goto out_err; 71662306a36Sopenharmony_ci read += ret; 71762306a36Sopenharmony_ci if (transport->recv.offset < transport->recv.len) { 71862306a36Sopenharmony_ci if (!(msg.msg_flags & MSG_TRUNC)) 71962306a36Sopenharmony_ci return read; 72062306a36Sopenharmony_ci msg.msg_flags = 0; 72162306a36Sopenharmony_ci ret = xs_read_discard(transport->sock, &msg, flags, 72262306a36Sopenharmony_ci transport->recv.len - transport->recv.offset); 72362306a36Sopenharmony_ci if (ret <= 0) 72462306a36Sopenharmony_ci goto out_err; 72562306a36Sopenharmony_ci transport->recv.offset += ret; 72662306a36Sopenharmony_ci read += ret; 72762306a36Sopenharmony_ci if (transport->recv.offset != transport->recv.len) 72862306a36Sopenharmony_ci return read; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci if (xs_read_stream_request_done(transport)) { 73162306a36Sopenharmony_ci trace_xs_stream_read_request(transport); 73262306a36Sopenharmony_ci transport->recv.copied = 0; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci transport->recv.offset = 0; 73562306a36Sopenharmony_ci transport->recv.len = 0; 73662306a36Sopenharmony_ci return read; 73762306a36Sopenharmony_ciout_err: 73862306a36Sopenharmony_ci return ret != 0 ? ret : -ESHUTDOWN; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic __poll_t xs_poll_socket(struct sock_xprt *transport) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci return transport->sock->ops->poll(transport->file, transport->sock, 74462306a36Sopenharmony_ci NULL); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic bool xs_poll_socket_readable(struct sock_xprt *transport) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci __poll_t events = xs_poll_socket(transport); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return (events & (EPOLLIN | EPOLLRDNORM)) && !(events & EPOLLRDHUP); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic void xs_poll_check_readable(struct sock_xprt *transport) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); 75862306a36Sopenharmony_ci if (test_bit(XPRT_SOCK_IGNORE_RECV, &transport->sock_state)) 75962306a36Sopenharmony_ci return; 76062306a36Sopenharmony_ci if (!xs_poll_socket_readable(transport)) 76162306a36Sopenharmony_ci return; 76262306a36Sopenharmony_ci if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) 76362306a36Sopenharmony_ci queue_work(xprtiod_workqueue, &transport->recv_worker); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic void xs_stream_data_receive(struct sock_xprt *transport) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci size_t read = 0; 76962306a36Sopenharmony_ci ssize_t ret = 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci mutex_lock(&transport->recv_mutex); 77262306a36Sopenharmony_ci if (transport->sock == NULL) 77362306a36Sopenharmony_ci goto out; 77462306a36Sopenharmony_ci for (;;) { 77562306a36Sopenharmony_ci ret = xs_read_stream(transport, MSG_DONTWAIT); 77662306a36Sopenharmony_ci if (ret < 0) 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci read += ret; 77962306a36Sopenharmony_ci cond_resched(); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci if (ret == -ESHUTDOWN) 78262306a36Sopenharmony_ci kernel_sock_shutdown(transport->sock, SHUT_RDWR); 78362306a36Sopenharmony_ci else if (ret == -EACCES) 78462306a36Sopenharmony_ci xprt_wake_pending_tasks(&transport->xprt, -EACCES); 78562306a36Sopenharmony_ci else 78662306a36Sopenharmony_ci xs_poll_check_readable(transport); 78762306a36Sopenharmony_ciout: 78862306a36Sopenharmony_ci mutex_unlock(&transport->recv_mutex); 78962306a36Sopenharmony_ci trace_xs_stream_read_data(&transport->xprt, ret, read); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic void xs_stream_data_receive_workfn(struct work_struct *work) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct sock_xprt *transport = 79562306a36Sopenharmony_ci container_of(work, struct sock_xprt, recv_worker); 79662306a36Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci xs_stream_data_receive(transport); 79962306a36Sopenharmony_ci memalloc_nofs_restore(pflags); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void 80362306a36Sopenharmony_cixs_stream_reset_connect(struct sock_xprt *transport) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci transport->recv.offset = 0; 80662306a36Sopenharmony_ci transport->recv.len = 0; 80762306a36Sopenharmony_ci transport->recv.copied = 0; 80862306a36Sopenharmony_ci transport->xmit.offset = 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic void 81262306a36Sopenharmony_cixs_stream_start_connect(struct sock_xprt *transport) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci transport->xprt.stat.connect_count++; 81562306a36Sopenharmony_ci transport->xprt.stat.connect_start = jiffies; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci#define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/** 82162306a36Sopenharmony_ci * xs_nospace - handle transmit was incomplete 82262306a36Sopenharmony_ci * @req: pointer to RPC request 82362306a36Sopenharmony_ci * @transport: pointer to struct sock_xprt 82462306a36Sopenharmony_ci * 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_cistatic int xs_nospace(struct rpc_rqst *req, struct sock_xprt *transport) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 82962306a36Sopenharmony_ci struct sock *sk = transport->inet; 83062306a36Sopenharmony_ci int ret = -EAGAIN; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci trace_rpc_socket_nospace(req, transport); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* Protect against races with write_space */ 83562306a36Sopenharmony_ci spin_lock(&xprt->transport_lock); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* Don't race with disconnect */ 83862306a36Sopenharmony_ci if (xprt_connected(xprt)) { 83962306a36Sopenharmony_ci /* wait for more buffer space */ 84062306a36Sopenharmony_ci set_bit(XPRT_SOCK_NOSPACE, &transport->sock_state); 84162306a36Sopenharmony_ci set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 84262306a36Sopenharmony_ci sk->sk_write_pending++; 84362306a36Sopenharmony_ci xprt_wait_for_buffer_space(xprt); 84462306a36Sopenharmony_ci } else 84562306a36Sopenharmony_ci ret = -ENOTCONN; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci spin_unlock(&xprt->transport_lock); 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic int xs_sock_nospace(struct rpc_rqst *req) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct sock_xprt *transport = 85462306a36Sopenharmony_ci container_of(req->rq_xprt, struct sock_xprt, xprt); 85562306a36Sopenharmony_ci struct sock *sk = transport->inet; 85662306a36Sopenharmony_ci int ret = -EAGAIN; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci lock_sock(sk); 85962306a36Sopenharmony_ci if (!sock_writeable(sk)) 86062306a36Sopenharmony_ci ret = xs_nospace(req, transport); 86162306a36Sopenharmony_ci release_sock(sk); 86262306a36Sopenharmony_ci return ret; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int xs_stream_nospace(struct rpc_rqst *req, bool vm_wait) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct sock_xprt *transport = 86862306a36Sopenharmony_ci container_of(req->rq_xprt, struct sock_xprt, xprt); 86962306a36Sopenharmony_ci struct sock *sk = transport->inet; 87062306a36Sopenharmony_ci int ret = -EAGAIN; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (vm_wait) 87362306a36Sopenharmony_ci return -ENOBUFS; 87462306a36Sopenharmony_ci lock_sock(sk); 87562306a36Sopenharmony_ci if (!sk_stream_memory_free(sk)) 87662306a36Sopenharmony_ci ret = xs_nospace(req, transport); 87762306a36Sopenharmony_ci release_sock(sk); 87862306a36Sopenharmony_ci return ret; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int xs_stream_prepare_request(struct rpc_rqst *req, struct xdr_buf *buf) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci return xdr_alloc_bvec(buf, rpc_task_gfp_mask()); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/* 88762306a36Sopenharmony_ci * Determine if the previous message in the stream was aborted before it 88862306a36Sopenharmony_ci * could complete transmission. 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_cistatic bool 89162306a36Sopenharmony_cixs_send_request_was_aborted(struct sock_xprt *transport, struct rpc_rqst *req) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci return transport->xmit.offset != 0 && req->rq_bytes_sent == 0; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci/* 89762306a36Sopenharmony_ci * Return the stream record marker field for a record of length < 2^31-1 89862306a36Sopenharmony_ci */ 89962306a36Sopenharmony_cistatic rpc_fraghdr 90062306a36Sopenharmony_cixs_stream_record_marker(struct xdr_buf *xdr) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci if (!xdr->len) 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci return cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | (u32)xdr->len); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/** 90862306a36Sopenharmony_ci * xs_local_send_request - write an RPC request to an AF_LOCAL socket 90962306a36Sopenharmony_ci * @req: pointer to RPC request 91062306a36Sopenharmony_ci * 91162306a36Sopenharmony_ci * Return values: 91262306a36Sopenharmony_ci * 0: The request has been sent 91362306a36Sopenharmony_ci * EAGAIN: The socket was blocked, please call again later to 91462306a36Sopenharmony_ci * complete the request 91562306a36Sopenharmony_ci * ENOTCONN: Caller needs to invoke connect logic then call again 91662306a36Sopenharmony_ci * other: Some other error occurred, the request was not sent 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_cistatic int xs_local_send_request(struct rpc_rqst *req) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct rpc_xprt *xprt = req->rq_xprt; 92162306a36Sopenharmony_ci struct sock_xprt *transport = 92262306a36Sopenharmony_ci container_of(xprt, struct sock_xprt, xprt); 92362306a36Sopenharmony_ci struct xdr_buf *xdr = &req->rq_snd_buf; 92462306a36Sopenharmony_ci rpc_fraghdr rm = xs_stream_record_marker(xdr); 92562306a36Sopenharmony_ci unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen; 92662306a36Sopenharmony_ci struct msghdr msg = { 92762306a36Sopenharmony_ci .msg_flags = XS_SENDMSG_FLAGS, 92862306a36Sopenharmony_ci }; 92962306a36Sopenharmony_ci bool vm_wait; 93062306a36Sopenharmony_ci unsigned int sent; 93162306a36Sopenharmony_ci int status; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Close the stream if the previous transmission was incomplete */ 93462306a36Sopenharmony_ci if (xs_send_request_was_aborted(transport, req)) { 93562306a36Sopenharmony_ci xprt_force_disconnect(xprt); 93662306a36Sopenharmony_ci return -ENOTCONN; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci xs_pktdump("packet data:", 94062306a36Sopenharmony_ci req->rq_svec->iov_base, req->rq_svec->iov_len); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci vm_wait = sk_stream_is_writeable(transport->inet) ? true : false; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci req->rq_xtime = ktime_get(); 94562306a36Sopenharmony_ci status = xprt_sock_sendmsg(transport->sock, &msg, xdr, 94662306a36Sopenharmony_ci transport->xmit.offset, rm, &sent); 94762306a36Sopenharmony_ci dprintk("RPC: %s(%u) = %d\n", 94862306a36Sopenharmony_ci __func__, xdr->len - transport->xmit.offset, status); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (likely(sent > 0) || status == 0) { 95162306a36Sopenharmony_ci transport->xmit.offset += sent; 95262306a36Sopenharmony_ci req->rq_bytes_sent = transport->xmit.offset; 95362306a36Sopenharmony_ci if (likely(req->rq_bytes_sent >= msglen)) { 95462306a36Sopenharmony_ci req->rq_xmit_bytes_sent += transport->xmit.offset; 95562306a36Sopenharmony_ci transport->xmit.offset = 0; 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci status = -EAGAIN; 95962306a36Sopenharmony_ci vm_wait = false; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci switch (status) { 96362306a36Sopenharmony_ci case -EAGAIN: 96462306a36Sopenharmony_ci status = xs_stream_nospace(req, vm_wait); 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci default: 96762306a36Sopenharmony_ci dprintk("RPC: sendmsg returned unrecognized error %d\n", 96862306a36Sopenharmony_ci -status); 96962306a36Sopenharmony_ci fallthrough; 97062306a36Sopenharmony_ci case -EPIPE: 97162306a36Sopenharmony_ci xprt_force_disconnect(xprt); 97262306a36Sopenharmony_ci status = -ENOTCONN; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci return status; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci/** 97962306a36Sopenharmony_ci * xs_udp_send_request - write an RPC request to a UDP socket 98062306a36Sopenharmony_ci * @req: pointer to RPC request 98162306a36Sopenharmony_ci * 98262306a36Sopenharmony_ci * Return values: 98362306a36Sopenharmony_ci * 0: The request has been sent 98462306a36Sopenharmony_ci * EAGAIN: The socket was blocked, please call again later to 98562306a36Sopenharmony_ci * complete the request 98662306a36Sopenharmony_ci * ENOTCONN: Caller needs to invoke connect logic then call again 98762306a36Sopenharmony_ci * other: Some other error occurred, the request was not sent 98862306a36Sopenharmony_ci */ 98962306a36Sopenharmony_cistatic int xs_udp_send_request(struct rpc_rqst *req) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct rpc_xprt *xprt = req->rq_xprt; 99262306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 99362306a36Sopenharmony_ci struct xdr_buf *xdr = &req->rq_snd_buf; 99462306a36Sopenharmony_ci struct msghdr msg = { 99562306a36Sopenharmony_ci .msg_name = xs_addr(xprt), 99662306a36Sopenharmony_ci .msg_namelen = xprt->addrlen, 99762306a36Sopenharmony_ci .msg_flags = XS_SENDMSG_FLAGS, 99862306a36Sopenharmony_ci }; 99962306a36Sopenharmony_ci unsigned int sent; 100062306a36Sopenharmony_ci int status; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci xs_pktdump("packet data:", 100362306a36Sopenharmony_ci req->rq_svec->iov_base, 100462306a36Sopenharmony_ci req->rq_svec->iov_len); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (!xprt_bound(xprt)) 100762306a36Sopenharmony_ci return -ENOTCONN; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!xprt_request_get_cong(xprt, req)) 101062306a36Sopenharmony_ci return -EBADSLT; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci status = xdr_alloc_bvec(xdr, rpc_task_gfp_mask()); 101362306a36Sopenharmony_ci if (status < 0) 101462306a36Sopenharmony_ci return status; 101562306a36Sopenharmony_ci req->rq_xtime = ktime_get(); 101662306a36Sopenharmony_ci status = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, 0, &sent); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci dprintk("RPC: xs_udp_send_request(%u) = %d\n", 101962306a36Sopenharmony_ci xdr->len, status); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* firewall is blocking us, don't return -EAGAIN or we end up looping */ 102262306a36Sopenharmony_ci if (status == -EPERM) 102362306a36Sopenharmony_ci goto process_status; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (status == -EAGAIN && sock_writeable(transport->inet)) 102662306a36Sopenharmony_ci status = -ENOBUFS; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (sent > 0 || status == 0) { 102962306a36Sopenharmony_ci req->rq_xmit_bytes_sent += sent; 103062306a36Sopenharmony_ci if (sent >= req->rq_slen) 103162306a36Sopenharmony_ci return 0; 103262306a36Sopenharmony_ci /* Still some bytes left; set up for a retry later. */ 103362306a36Sopenharmony_ci status = -EAGAIN; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ciprocess_status: 103762306a36Sopenharmony_ci switch (status) { 103862306a36Sopenharmony_ci case -ENOTSOCK: 103962306a36Sopenharmony_ci status = -ENOTCONN; 104062306a36Sopenharmony_ci /* Should we call xs_close() here? */ 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case -EAGAIN: 104362306a36Sopenharmony_ci status = xs_sock_nospace(req); 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci case -ENETUNREACH: 104662306a36Sopenharmony_ci case -ENOBUFS: 104762306a36Sopenharmony_ci case -EPIPE: 104862306a36Sopenharmony_ci case -ECONNREFUSED: 104962306a36Sopenharmony_ci case -EPERM: 105062306a36Sopenharmony_ci /* When the server has died, an ICMP port unreachable message 105162306a36Sopenharmony_ci * prompts ECONNREFUSED. */ 105262306a36Sopenharmony_ci break; 105362306a36Sopenharmony_ci default: 105462306a36Sopenharmony_ci dprintk("RPC: sendmsg returned unrecognized error %d\n", 105562306a36Sopenharmony_ci -status); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return status; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci/** 106262306a36Sopenharmony_ci * xs_tcp_send_request - write an RPC request to a TCP socket 106362306a36Sopenharmony_ci * @req: pointer to RPC request 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * Return values: 106662306a36Sopenharmony_ci * 0: The request has been sent 106762306a36Sopenharmony_ci * EAGAIN: The socket was blocked, please call again later to 106862306a36Sopenharmony_ci * complete the request 106962306a36Sopenharmony_ci * ENOTCONN: Caller needs to invoke connect logic then call again 107062306a36Sopenharmony_ci * other: Some other error occurred, the request was not sent 107162306a36Sopenharmony_ci * 107262306a36Sopenharmony_ci * XXX: In the case of soft timeouts, should we eventually give up 107362306a36Sopenharmony_ci * if sendmsg is not able to make progress? 107462306a36Sopenharmony_ci */ 107562306a36Sopenharmony_cistatic int xs_tcp_send_request(struct rpc_rqst *req) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct rpc_xprt *xprt = req->rq_xprt; 107862306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 107962306a36Sopenharmony_ci struct xdr_buf *xdr = &req->rq_snd_buf; 108062306a36Sopenharmony_ci rpc_fraghdr rm = xs_stream_record_marker(xdr); 108162306a36Sopenharmony_ci unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen; 108262306a36Sopenharmony_ci struct msghdr msg = { 108362306a36Sopenharmony_ci .msg_flags = XS_SENDMSG_FLAGS, 108462306a36Sopenharmony_ci }; 108562306a36Sopenharmony_ci bool vm_wait; 108662306a36Sopenharmony_ci unsigned int sent; 108762306a36Sopenharmony_ci int status; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* Close the stream if the previous transmission was incomplete */ 109062306a36Sopenharmony_ci if (xs_send_request_was_aborted(transport, req)) { 109162306a36Sopenharmony_ci if (transport->sock != NULL) 109262306a36Sopenharmony_ci kernel_sock_shutdown(transport->sock, SHUT_RDWR); 109362306a36Sopenharmony_ci return -ENOTCONN; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci if (!transport->inet) 109662306a36Sopenharmony_ci return -ENOTCONN; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci xs_pktdump("packet data:", 109962306a36Sopenharmony_ci req->rq_svec->iov_base, 110062306a36Sopenharmony_ci req->rq_svec->iov_len); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state)) 110362306a36Sopenharmony_ci xs_tcp_set_socket_timeouts(xprt, transport->sock); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci xs_set_srcport(transport, transport->sock); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Continue transmitting the packet/record. We must be careful 110862306a36Sopenharmony_ci * to cope with writespace callbacks arriving _after_ we have 110962306a36Sopenharmony_ci * called sendmsg(). */ 111062306a36Sopenharmony_ci req->rq_xtime = ktime_get(); 111162306a36Sopenharmony_ci tcp_sock_set_cork(transport->inet, true); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci vm_wait = sk_stream_is_writeable(transport->inet) ? true : false; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci do { 111662306a36Sopenharmony_ci status = xprt_sock_sendmsg(transport->sock, &msg, xdr, 111762306a36Sopenharmony_ci transport->xmit.offset, rm, &sent); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci dprintk("RPC: xs_tcp_send_request(%u) = %d\n", 112062306a36Sopenharmony_ci xdr->len - transport->xmit.offset, status); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* If we've sent the entire packet, immediately 112362306a36Sopenharmony_ci * reset the count of bytes sent. */ 112462306a36Sopenharmony_ci transport->xmit.offset += sent; 112562306a36Sopenharmony_ci req->rq_bytes_sent = transport->xmit.offset; 112662306a36Sopenharmony_ci if (likely(req->rq_bytes_sent >= msglen)) { 112762306a36Sopenharmony_ci req->rq_xmit_bytes_sent += transport->xmit.offset; 112862306a36Sopenharmony_ci transport->xmit.offset = 0; 112962306a36Sopenharmony_ci if (atomic_long_read(&xprt->xmit_queuelen) == 1) 113062306a36Sopenharmony_ci tcp_sock_set_cork(transport->inet, false); 113162306a36Sopenharmony_ci return 0; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci WARN_ON_ONCE(sent == 0 && status == 0); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (sent > 0) 113762306a36Sopenharmony_ci vm_wait = false; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci } while (status == 0); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci switch (status) { 114262306a36Sopenharmony_ci case -ENOTSOCK: 114362306a36Sopenharmony_ci status = -ENOTCONN; 114462306a36Sopenharmony_ci /* Should we call xs_close() here? */ 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci case -EAGAIN: 114762306a36Sopenharmony_ci status = xs_stream_nospace(req, vm_wait); 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci case -ECONNRESET: 115062306a36Sopenharmony_ci case -ECONNREFUSED: 115162306a36Sopenharmony_ci case -ENOTCONN: 115262306a36Sopenharmony_ci case -EADDRINUSE: 115362306a36Sopenharmony_ci case -ENOBUFS: 115462306a36Sopenharmony_ci case -EPIPE: 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci default: 115762306a36Sopenharmony_ci dprintk("RPC: sendmsg returned unrecognized error %d\n", 115862306a36Sopenharmony_ci -status); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return status; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci transport->old_data_ready = sk->sk_data_ready; 116762306a36Sopenharmony_ci transport->old_state_change = sk->sk_state_change; 116862306a36Sopenharmony_ci transport->old_write_space = sk->sk_write_space; 116962306a36Sopenharmony_ci transport->old_error_report = sk->sk_error_report; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci sk->sk_data_ready = transport->old_data_ready; 117562306a36Sopenharmony_ci sk->sk_state_change = transport->old_state_change; 117662306a36Sopenharmony_ci sk->sk_write_space = transport->old_write_space; 117762306a36Sopenharmony_ci sk->sk_error_report = transport->old_error_report; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic void xs_sock_reset_state_flags(struct rpc_xprt *xprt) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); 118562306a36Sopenharmony_ci clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state); 118662306a36Sopenharmony_ci clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state); 118762306a36Sopenharmony_ci clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state); 118862306a36Sopenharmony_ci clear_bit(XPRT_SOCK_NOSPACE, &transport->sock_state); 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic void xs_run_error_worker(struct sock_xprt *transport, unsigned int nr) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci set_bit(nr, &transport->sock_state); 119462306a36Sopenharmony_ci queue_work(xprtiod_workqueue, &transport->error_worker); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic void xs_sock_reset_connection_flags(struct rpc_xprt *xprt) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci xprt->connect_cookie++; 120062306a36Sopenharmony_ci smp_mb__before_atomic(); 120162306a36Sopenharmony_ci clear_bit(XPRT_CLOSE_WAIT, &xprt->state); 120262306a36Sopenharmony_ci clear_bit(XPRT_CLOSING, &xprt->state); 120362306a36Sopenharmony_ci xs_sock_reset_state_flags(xprt); 120462306a36Sopenharmony_ci smp_mb__after_atomic(); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci/** 120862306a36Sopenharmony_ci * xs_error_report - callback to handle TCP socket state errors 120962306a36Sopenharmony_ci * @sk: socket 121062306a36Sopenharmony_ci * 121162306a36Sopenharmony_ci * Note: we don't call sock_error() since there may be a rpc_task 121262306a36Sopenharmony_ci * using the socket, and so we don't want to clear sk->sk_err. 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_cistatic void xs_error_report(struct sock *sk) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct sock_xprt *transport; 121762306a36Sopenharmony_ci struct rpc_xprt *xprt; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (!(xprt = xprt_from_sock(sk))) 122062306a36Sopenharmony_ci return; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 122362306a36Sopenharmony_ci transport->xprt_err = -sk->sk_err; 122462306a36Sopenharmony_ci if (transport->xprt_err == 0) 122562306a36Sopenharmony_ci return; 122662306a36Sopenharmony_ci dprintk("RPC: xs_error_report client %p, error=%d...\n", 122762306a36Sopenharmony_ci xprt, -transport->xprt_err); 122862306a36Sopenharmony_ci trace_rpc_socket_error(xprt, sk->sk_socket, transport->xprt_err); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* barrier ensures xprt_err is set before XPRT_SOCK_WAKE_ERROR */ 123162306a36Sopenharmony_ci smp_mb__before_atomic(); 123262306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_ERROR); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic void xs_reset_transport(struct sock_xprt *transport) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct socket *sock = transport->sock; 123862306a36Sopenharmony_ci struct sock *sk = transport->inet; 123962306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 124062306a36Sopenharmony_ci struct file *filp = transport->file; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (sk == NULL) 124362306a36Sopenharmony_ci return; 124462306a36Sopenharmony_ci /* 124562306a36Sopenharmony_ci * Make sure we're calling this in a context from which it is safe 124662306a36Sopenharmony_ci * to call __fput_sync(). In practice that means rpciod and the 124762306a36Sopenharmony_ci * system workqueue. 124862306a36Sopenharmony_ci */ 124962306a36Sopenharmony_ci if (!(current->flags & PF_WQ_WORKER)) { 125062306a36Sopenharmony_ci WARN_ON_ONCE(1); 125162306a36Sopenharmony_ci set_bit(XPRT_CLOSE_WAIT, &xprt->state); 125262306a36Sopenharmony_ci return; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (atomic_read(&transport->xprt.swapper)) 125662306a36Sopenharmony_ci sk_clear_memalloc(sk); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci tls_handshake_cancel(sk); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci mutex_lock(&transport->recv_mutex); 126362306a36Sopenharmony_ci lock_sock(sk); 126462306a36Sopenharmony_ci transport->inet = NULL; 126562306a36Sopenharmony_ci transport->sock = NULL; 126662306a36Sopenharmony_ci transport->file = NULL; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci sk->sk_user_data = NULL; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci xs_restore_old_callbacks(transport, sk); 127162306a36Sopenharmony_ci xprt_clear_connected(xprt); 127262306a36Sopenharmony_ci xs_sock_reset_connection_flags(xprt); 127362306a36Sopenharmony_ci /* Reset stream record info */ 127462306a36Sopenharmony_ci xs_stream_reset_connect(transport); 127562306a36Sopenharmony_ci release_sock(sk); 127662306a36Sopenharmony_ci mutex_unlock(&transport->recv_mutex); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci trace_rpc_socket_close(xprt, sock); 127962306a36Sopenharmony_ci __fput_sync(filp); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci xprt_disconnect_done(xprt); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci/** 128562306a36Sopenharmony_ci * xs_close - close a socket 128662306a36Sopenharmony_ci * @xprt: transport 128762306a36Sopenharmony_ci * 128862306a36Sopenharmony_ci * This is used when all requests are complete; ie, no DRC state remains 128962306a36Sopenharmony_ci * on the server we want to save. 129062306a36Sopenharmony_ci * 129162306a36Sopenharmony_ci * The caller _must_ be holding XPRT_LOCKED in order to avoid issues with 129262306a36Sopenharmony_ci * xs_reset_transport() zeroing the socket from underneath a writer. 129362306a36Sopenharmony_ci */ 129462306a36Sopenharmony_cistatic void xs_close(struct rpc_xprt *xprt) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci dprintk("RPC: xs_close xprt %p\n", xprt); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (transport->sock) 130162306a36Sopenharmony_ci tls_handshake_close(transport->sock); 130262306a36Sopenharmony_ci xs_reset_transport(transport); 130362306a36Sopenharmony_ci xprt->reestablish_timeout = 0; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic void xs_inject_disconnect(struct rpc_xprt *xprt) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci dprintk("RPC: injecting transport disconnect on xprt=%p\n", 130962306a36Sopenharmony_ci xprt); 131062306a36Sopenharmony_ci xprt_disconnect_done(xprt); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic void xs_xprt_free(struct rpc_xprt *xprt) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci xs_free_peer_addresses(xprt); 131662306a36Sopenharmony_ci xprt_free(xprt); 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci/** 132062306a36Sopenharmony_ci * xs_destroy - prepare to shutdown a transport 132162306a36Sopenharmony_ci * @xprt: doomed transport 132262306a36Sopenharmony_ci * 132362306a36Sopenharmony_ci */ 132462306a36Sopenharmony_cistatic void xs_destroy(struct rpc_xprt *xprt) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, 132762306a36Sopenharmony_ci struct sock_xprt, xprt); 132862306a36Sopenharmony_ci dprintk("RPC: xs_destroy xprt %p\n", xprt); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci cancel_delayed_work_sync(&transport->connect_worker); 133162306a36Sopenharmony_ci xs_close(xprt); 133262306a36Sopenharmony_ci cancel_work_sync(&transport->recv_worker); 133362306a36Sopenharmony_ci cancel_work_sync(&transport->error_worker); 133462306a36Sopenharmony_ci xs_xprt_free(xprt); 133562306a36Sopenharmony_ci module_put(THIS_MODULE); 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci/** 133962306a36Sopenharmony_ci * xs_udp_data_read_skb - receive callback for UDP sockets 134062306a36Sopenharmony_ci * @xprt: transport 134162306a36Sopenharmony_ci * @sk: socket 134262306a36Sopenharmony_ci * @skb: skbuff 134362306a36Sopenharmony_ci * 134462306a36Sopenharmony_ci */ 134562306a36Sopenharmony_cistatic void xs_udp_data_read_skb(struct rpc_xprt *xprt, 134662306a36Sopenharmony_ci struct sock *sk, 134762306a36Sopenharmony_ci struct sk_buff *skb) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct rpc_task *task; 135062306a36Sopenharmony_ci struct rpc_rqst *rovr; 135162306a36Sopenharmony_ci int repsize, copied; 135262306a36Sopenharmony_ci u32 _xid; 135362306a36Sopenharmony_ci __be32 *xp; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci repsize = skb->len; 135662306a36Sopenharmony_ci if (repsize < 4) { 135762306a36Sopenharmony_ci dprintk("RPC: impossible RPC reply size %d!\n", repsize); 135862306a36Sopenharmony_ci return; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci /* Copy the XID from the skb... */ 136262306a36Sopenharmony_ci xp = skb_header_pointer(skb, 0, sizeof(_xid), &_xid); 136362306a36Sopenharmony_ci if (xp == NULL) 136462306a36Sopenharmony_ci return; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* Look up and lock the request corresponding to the given XID */ 136762306a36Sopenharmony_ci spin_lock(&xprt->queue_lock); 136862306a36Sopenharmony_ci rovr = xprt_lookup_rqst(xprt, *xp); 136962306a36Sopenharmony_ci if (!rovr) 137062306a36Sopenharmony_ci goto out_unlock; 137162306a36Sopenharmony_ci xprt_pin_rqst(rovr); 137262306a36Sopenharmony_ci xprt_update_rtt(rovr->rq_task); 137362306a36Sopenharmony_ci spin_unlock(&xprt->queue_lock); 137462306a36Sopenharmony_ci task = rovr->rq_task; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if ((copied = rovr->rq_private_buf.buflen) > repsize) 137762306a36Sopenharmony_ci copied = repsize; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* Suck it into the iovec, verify checksum if not done by hw. */ 138062306a36Sopenharmony_ci if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) { 138162306a36Sopenharmony_ci spin_lock(&xprt->queue_lock); 138262306a36Sopenharmony_ci __UDPX_INC_STATS(sk, UDP_MIB_INERRORS); 138362306a36Sopenharmony_ci goto out_unpin; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci spin_lock(&xprt->transport_lock); 138862306a36Sopenharmony_ci xprt_adjust_cwnd(xprt, task, copied); 138962306a36Sopenharmony_ci spin_unlock(&xprt->transport_lock); 139062306a36Sopenharmony_ci spin_lock(&xprt->queue_lock); 139162306a36Sopenharmony_ci xprt_complete_rqst(task, copied); 139262306a36Sopenharmony_ci __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS); 139362306a36Sopenharmony_ciout_unpin: 139462306a36Sopenharmony_ci xprt_unpin_rqst(rovr); 139562306a36Sopenharmony_ci out_unlock: 139662306a36Sopenharmony_ci spin_unlock(&xprt->queue_lock); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic void xs_udp_data_receive(struct sock_xprt *transport) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci struct sk_buff *skb; 140262306a36Sopenharmony_ci struct sock *sk; 140362306a36Sopenharmony_ci int err; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci mutex_lock(&transport->recv_mutex); 140662306a36Sopenharmony_ci sk = transport->inet; 140762306a36Sopenharmony_ci if (sk == NULL) 140862306a36Sopenharmony_ci goto out; 140962306a36Sopenharmony_ci for (;;) { 141062306a36Sopenharmony_ci skb = skb_recv_udp(sk, MSG_DONTWAIT, &err); 141162306a36Sopenharmony_ci if (skb == NULL) 141262306a36Sopenharmony_ci break; 141362306a36Sopenharmony_ci xs_udp_data_read_skb(&transport->xprt, sk, skb); 141462306a36Sopenharmony_ci consume_skb(skb); 141562306a36Sopenharmony_ci cond_resched(); 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci xs_poll_check_readable(transport); 141862306a36Sopenharmony_ciout: 141962306a36Sopenharmony_ci mutex_unlock(&transport->recv_mutex); 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistatic void xs_udp_data_receive_workfn(struct work_struct *work) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct sock_xprt *transport = 142562306a36Sopenharmony_ci container_of(work, struct sock_xprt, recv_worker); 142662306a36Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci xs_udp_data_receive(transport); 142962306a36Sopenharmony_ci memalloc_nofs_restore(pflags); 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/** 143362306a36Sopenharmony_ci * xs_data_ready - "data ready" callback for sockets 143462306a36Sopenharmony_ci * @sk: socket with data to read 143562306a36Sopenharmony_ci * 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_cistatic void xs_data_ready(struct sock *sk) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci struct rpc_xprt *xprt; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci trace_sk_data_ready(sk); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci xprt = xprt_from_sock(sk); 144462306a36Sopenharmony_ci if (xprt != NULL) { 144562306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, 144662306a36Sopenharmony_ci struct sock_xprt, xprt); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci trace_xs_data_ready(xprt); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci transport->old_data_ready(sk); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (test_bit(XPRT_SOCK_IGNORE_RECV, &transport->sock_state)) 145362306a36Sopenharmony_ci return; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* Any data means we had a useful conversation, so 145662306a36Sopenharmony_ci * then we don't need to delay the next reconnect 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_ci if (xprt->reestablish_timeout) 145962306a36Sopenharmony_ci xprt->reestablish_timeout = 0; 146062306a36Sopenharmony_ci if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) 146162306a36Sopenharmony_ci queue_work(xprtiod_workqueue, &transport->recv_worker); 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci/* 146662306a36Sopenharmony_ci * Helper function to force a TCP close if the server is sending 146762306a36Sopenharmony_ci * junk and/or it has put us in CLOSE_WAIT 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_cistatic void xs_tcp_force_close(struct rpc_xprt *xprt) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci xprt_force_disconnect(xprt); 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL) 147562306a36Sopenharmony_cistatic size_t xs_tcp_bc_maxpayload(struct rpc_xprt *xprt) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci return PAGE_SIZE; 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */ 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci/** 148262306a36Sopenharmony_ci * xs_local_state_change - callback to handle AF_LOCAL socket state changes 148362306a36Sopenharmony_ci * @sk: socket whose state has changed 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci */ 148662306a36Sopenharmony_cistatic void xs_local_state_change(struct sock *sk) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci struct rpc_xprt *xprt; 148962306a36Sopenharmony_ci struct sock_xprt *transport; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (!(xprt = xprt_from_sock(sk))) 149262306a36Sopenharmony_ci return; 149362306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 149462306a36Sopenharmony_ci if (sk->sk_shutdown & SHUTDOWN_MASK) { 149562306a36Sopenharmony_ci clear_bit(XPRT_CONNECTED, &xprt->state); 149662306a36Sopenharmony_ci /* Trigger the socket release */ 149762306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT); 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci/** 150262306a36Sopenharmony_ci * xs_tcp_state_change - callback to handle TCP socket state changes 150362306a36Sopenharmony_ci * @sk: socket whose state has changed 150462306a36Sopenharmony_ci * 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_cistatic void xs_tcp_state_change(struct sock *sk) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct rpc_xprt *xprt; 150962306a36Sopenharmony_ci struct sock_xprt *transport; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (!(xprt = xprt_from_sock(sk))) 151262306a36Sopenharmony_ci return; 151362306a36Sopenharmony_ci dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); 151462306a36Sopenharmony_ci dprintk("RPC: state %x conn %d dead %d zapped %d sk_shutdown %d\n", 151562306a36Sopenharmony_ci sk->sk_state, xprt_connected(xprt), 151662306a36Sopenharmony_ci sock_flag(sk, SOCK_DEAD), 151762306a36Sopenharmony_ci sock_flag(sk, SOCK_ZAPPED), 151862306a36Sopenharmony_ci sk->sk_shutdown); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 152162306a36Sopenharmony_ci trace_rpc_socket_state_change(xprt, sk->sk_socket); 152262306a36Sopenharmony_ci switch (sk->sk_state) { 152362306a36Sopenharmony_ci case TCP_ESTABLISHED: 152462306a36Sopenharmony_ci if (!xprt_test_and_set_connected(xprt)) { 152562306a36Sopenharmony_ci xprt->connect_cookie++; 152662306a36Sopenharmony_ci clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); 152762306a36Sopenharmony_ci xprt_clear_connecting(xprt); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci xprt->stat.connect_count++; 153062306a36Sopenharmony_ci xprt->stat.connect_time += (long)jiffies - 153162306a36Sopenharmony_ci xprt->stat.connect_start; 153262306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_PENDING); 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci break; 153562306a36Sopenharmony_ci case TCP_FIN_WAIT1: 153662306a36Sopenharmony_ci /* The client initiated a shutdown of the socket */ 153762306a36Sopenharmony_ci xprt->connect_cookie++; 153862306a36Sopenharmony_ci xprt->reestablish_timeout = 0; 153962306a36Sopenharmony_ci set_bit(XPRT_CLOSING, &xprt->state); 154062306a36Sopenharmony_ci smp_mb__before_atomic(); 154162306a36Sopenharmony_ci clear_bit(XPRT_CONNECTED, &xprt->state); 154262306a36Sopenharmony_ci clear_bit(XPRT_CLOSE_WAIT, &xprt->state); 154362306a36Sopenharmony_ci smp_mb__after_atomic(); 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci case TCP_CLOSE_WAIT: 154662306a36Sopenharmony_ci /* The server initiated a shutdown of the socket */ 154762306a36Sopenharmony_ci xprt->connect_cookie++; 154862306a36Sopenharmony_ci clear_bit(XPRT_CONNECTED, &xprt->state); 154962306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT); 155062306a36Sopenharmony_ci fallthrough; 155162306a36Sopenharmony_ci case TCP_CLOSING: 155262306a36Sopenharmony_ci /* 155362306a36Sopenharmony_ci * If the server closed down the connection, make sure that 155462306a36Sopenharmony_ci * we back off before reconnecting 155562306a36Sopenharmony_ci */ 155662306a36Sopenharmony_ci if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) 155762306a36Sopenharmony_ci xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; 155862306a36Sopenharmony_ci break; 155962306a36Sopenharmony_ci case TCP_LAST_ACK: 156062306a36Sopenharmony_ci set_bit(XPRT_CLOSING, &xprt->state); 156162306a36Sopenharmony_ci smp_mb__before_atomic(); 156262306a36Sopenharmony_ci clear_bit(XPRT_CONNECTED, &xprt->state); 156362306a36Sopenharmony_ci smp_mb__after_atomic(); 156462306a36Sopenharmony_ci break; 156562306a36Sopenharmony_ci case TCP_CLOSE: 156662306a36Sopenharmony_ci if (test_and_clear_bit(XPRT_SOCK_CONNECTING, 156762306a36Sopenharmony_ci &transport->sock_state)) 156862306a36Sopenharmony_ci xprt_clear_connecting(xprt); 156962306a36Sopenharmony_ci clear_bit(XPRT_CLOSING, &xprt->state); 157062306a36Sopenharmony_ci /* Trigger the socket release */ 157162306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT); 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cistatic void xs_write_space(struct sock *sk) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct sock_xprt *transport; 157862306a36Sopenharmony_ci struct rpc_xprt *xprt; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (!sk->sk_socket) 158162306a36Sopenharmony_ci return; 158262306a36Sopenharmony_ci clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci if (unlikely(!(xprt = xprt_from_sock(sk)))) 158562306a36Sopenharmony_ci return; 158662306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 158762306a36Sopenharmony_ci if (!test_and_clear_bit(XPRT_SOCK_NOSPACE, &transport->sock_state)) 158862306a36Sopenharmony_ci return; 158962306a36Sopenharmony_ci xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE); 159062306a36Sopenharmony_ci sk->sk_write_pending--; 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci/** 159462306a36Sopenharmony_ci * xs_udp_write_space - callback invoked when socket buffer space 159562306a36Sopenharmony_ci * becomes available 159662306a36Sopenharmony_ci * @sk: socket whose state has changed 159762306a36Sopenharmony_ci * 159862306a36Sopenharmony_ci * Called when more output buffer space is available for this socket. 159962306a36Sopenharmony_ci * We try not to wake our writers until they can make "significant" 160062306a36Sopenharmony_ci * progress, otherwise we'll waste resources thrashing kernel_sendmsg 160162306a36Sopenharmony_ci * with a bunch of small requests. 160262306a36Sopenharmony_ci */ 160362306a36Sopenharmony_cistatic void xs_udp_write_space(struct sock *sk) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci /* from net/core/sock.c:sock_def_write_space */ 160662306a36Sopenharmony_ci if (sock_writeable(sk)) 160762306a36Sopenharmony_ci xs_write_space(sk); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci/** 161162306a36Sopenharmony_ci * xs_tcp_write_space - callback invoked when socket buffer space 161262306a36Sopenharmony_ci * becomes available 161362306a36Sopenharmony_ci * @sk: socket whose state has changed 161462306a36Sopenharmony_ci * 161562306a36Sopenharmony_ci * Called when more output buffer space is available for this socket. 161662306a36Sopenharmony_ci * We try not to wake our writers until they can make "significant" 161762306a36Sopenharmony_ci * progress, otherwise we'll waste resources thrashing kernel_sendmsg 161862306a36Sopenharmony_ci * with a bunch of small requests. 161962306a36Sopenharmony_ci */ 162062306a36Sopenharmony_cistatic void xs_tcp_write_space(struct sock *sk) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci /* from net/core/stream.c:sk_stream_write_space */ 162362306a36Sopenharmony_ci if (sk_stream_is_writeable(sk)) 162462306a36Sopenharmony_ci xs_write_space(sk); 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_cistatic void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 163062306a36Sopenharmony_ci struct sock *sk = transport->inet; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (transport->rcvsize) { 163362306a36Sopenharmony_ci sk->sk_userlocks |= SOCK_RCVBUF_LOCK; 163462306a36Sopenharmony_ci sk->sk_rcvbuf = transport->rcvsize * xprt->max_reqs * 2; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci if (transport->sndsize) { 163762306a36Sopenharmony_ci sk->sk_userlocks |= SOCK_SNDBUF_LOCK; 163862306a36Sopenharmony_ci sk->sk_sndbuf = transport->sndsize * xprt->max_reqs * 2; 163962306a36Sopenharmony_ci sk->sk_write_space(sk); 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci} 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci/** 164462306a36Sopenharmony_ci * xs_udp_set_buffer_size - set send and receive limits 164562306a36Sopenharmony_ci * @xprt: generic transport 164662306a36Sopenharmony_ci * @sndsize: requested size of send buffer, in bytes 164762306a36Sopenharmony_ci * @rcvsize: requested size of receive buffer, in bytes 164862306a36Sopenharmony_ci * 164962306a36Sopenharmony_ci * Set socket send and receive buffer size limits. 165062306a36Sopenharmony_ci */ 165162306a36Sopenharmony_cistatic void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize) 165262306a36Sopenharmony_ci{ 165362306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci transport->sndsize = 0; 165662306a36Sopenharmony_ci if (sndsize) 165762306a36Sopenharmony_ci transport->sndsize = sndsize + 1024; 165862306a36Sopenharmony_ci transport->rcvsize = 0; 165962306a36Sopenharmony_ci if (rcvsize) 166062306a36Sopenharmony_ci transport->rcvsize = rcvsize + 1024; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci xs_udp_do_set_buffer_size(xprt); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci/** 166662306a36Sopenharmony_ci * xs_udp_timer - called when a retransmit timeout occurs on a UDP transport 166762306a36Sopenharmony_ci * @xprt: controlling transport 166862306a36Sopenharmony_ci * @task: task that timed out 166962306a36Sopenharmony_ci * 167062306a36Sopenharmony_ci * Adjust the congestion window after a retransmit timeout has occurred. 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_cistatic void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci spin_lock(&xprt->transport_lock); 167562306a36Sopenharmony_ci xprt_adjust_cwnd(xprt, task, -ETIMEDOUT); 167662306a36Sopenharmony_ci spin_unlock(&xprt->transport_lock); 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic int xs_get_random_port(void) 168062306a36Sopenharmony_ci{ 168162306a36Sopenharmony_ci unsigned short min = xprt_min_resvport, max = xprt_max_resvport; 168262306a36Sopenharmony_ci unsigned short range; 168362306a36Sopenharmony_ci unsigned short rand; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if (max < min) 168662306a36Sopenharmony_ci return -EADDRINUSE; 168762306a36Sopenharmony_ci range = max - min + 1; 168862306a36Sopenharmony_ci rand = get_random_u32_below(range); 168962306a36Sopenharmony_ci return rand + min; 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_cistatic unsigned short xs_sock_getport(struct socket *sock) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct sockaddr_storage buf; 169562306a36Sopenharmony_ci unsigned short port = 0; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci if (kernel_getsockname(sock, (struct sockaddr *)&buf) < 0) 169862306a36Sopenharmony_ci goto out; 169962306a36Sopenharmony_ci switch (buf.ss_family) { 170062306a36Sopenharmony_ci case AF_INET6: 170162306a36Sopenharmony_ci port = ntohs(((struct sockaddr_in6 *)&buf)->sin6_port); 170262306a36Sopenharmony_ci break; 170362306a36Sopenharmony_ci case AF_INET: 170462306a36Sopenharmony_ci port = ntohs(((struct sockaddr_in *)&buf)->sin_port); 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ciout: 170762306a36Sopenharmony_ci return port; 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci/** 171162306a36Sopenharmony_ci * xs_set_port - reset the port number in the remote endpoint address 171262306a36Sopenharmony_ci * @xprt: generic transport 171362306a36Sopenharmony_ci * @port: new port number 171462306a36Sopenharmony_ci * 171562306a36Sopenharmony_ci */ 171662306a36Sopenharmony_cistatic void xs_set_port(struct rpc_xprt *xprt, unsigned short port) 171762306a36Sopenharmony_ci{ 171862306a36Sopenharmony_ci dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci rpc_set_port(xs_addr(xprt), port); 172162306a36Sopenharmony_ci xs_update_peer_port(xprt); 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_cistatic void xs_set_srcport(struct sock_xprt *transport, struct socket *sock) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci if (transport->srcport == 0 && transport->xprt.reuseport) 172762306a36Sopenharmony_ci transport->srcport = xs_sock_getport(sock); 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_cistatic int xs_get_srcport(struct sock_xprt *transport) 173162306a36Sopenharmony_ci{ 173262306a36Sopenharmony_ci int port = transport->srcport; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (port == 0 && transport->xprt.resvport) 173562306a36Sopenharmony_ci port = xs_get_random_port(); 173662306a36Sopenharmony_ci return port; 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_cistatic unsigned short xs_sock_srcport(struct rpc_xprt *xprt) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt); 174262306a36Sopenharmony_ci unsigned short ret = 0; 174362306a36Sopenharmony_ci mutex_lock(&sock->recv_mutex); 174462306a36Sopenharmony_ci if (sock->sock) 174562306a36Sopenharmony_ci ret = xs_sock_getport(sock->sock); 174662306a36Sopenharmony_ci mutex_unlock(&sock->recv_mutex); 174762306a36Sopenharmony_ci return ret; 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_cistatic int xs_sock_srcaddr(struct rpc_xprt *xprt, char *buf, size_t buflen) 175162306a36Sopenharmony_ci{ 175262306a36Sopenharmony_ci struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt); 175362306a36Sopenharmony_ci union { 175462306a36Sopenharmony_ci struct sockaddr sa; 175562306a36Sopenharmony_ci struct sockaddr_storage st; 175662306a36Sopenharmony_ci } saddr; 175762306a36Sopenharmony_ci int ret = -ENOTCONN; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci mutex_lock(&sock->recv_mutex); 176062306a36Sopenharmony_ci if (sock->sock) { 176162306a36Sopenharmony_ci ret = kernel_getsockname(sock->sock, &saddr.sa); 176262306a36Sopenharmony_ci if (ret >= 0) 176362306a36Sopenharmony_ci ret = snprintf(buf, buflen, "%pISc", &saddr.sa); 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci mutex_unlock(&sock->recv_mutex); 176662306a36Sopenharmony_ci return ret; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci if (transport->srcport != 0) 177262306a36Sopenharmony_ci transport->srcport = 0; 177362306a36Sopenharmony_ci if (!transport->xprt.resvport) 177462306a36Sopenharmony_ci return 0; 177562306a36Sopenharmony_ci if (port <= xprt_min_resvport || port > xprt_max_resvport) 177662306a36Sopenharmony_ci return xprt_max_resvport; 177762306a36Sopenharmony_ci return --port; 177862306a36Sopenharmony_ci} 177962306a36Sopenharmony_cistatic int xs_bind(struct sock_xprt *transport, struct socket *sock) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci struct sockaddr_storage myaddr; 178262306a36Sopenharmony_ci int err, nloop = 0; 178362306a36Sopenharmony_ci int port = xs_get_srcport(transport); 178462306a36Sopenharmony_ci unsigned short last; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* 178762306a36Sopenharmony_ci * If we are asking for any ephemeral port (i.e. port == 0 && 178862306a36Sopenharmony_ci * transport->xprt.resvport == 0), don't bind. Let the local 178962306a36Sopenharmony_ci * port selection happen implicitly when the socket is used 179062306a36Sopenharmony_ci * (for example at connect time). 179162306a36Sopenharmony_ci * 179262306a36Sopenharmony_ci * This ensures that we can continue to establish TCP 179362306a36Sopenharmony_ci * connections even when all local ephemeral ports are already 179462306a36Sopenharmony_ci * a part of some TCP connection. This makes no difference 179562306a36Sopenharmony_ci * for UDP sockets, but also doesn't harm them. 179662306a36Sopenharmony_ci * 179762306a36Sopenharmony_ci * If we're asking for any reserved port (i.e. port == 0 && 179862306a36Sopenharmony_ci * transport->xprt.resvport == 1) xs_get_srcport above will 179962306a36Sopenharmony_ci * ensure that port is non-zero and we will bind as needed. 180062306a36Sopenharmony_ci */ 180162306a36Sopenharmony_ci if (port <= 0) 180262306a36Sopenharmony_ci return port; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen); 180562306a36Sopenharmony_ci do { 180662306a36Sopenharmony_ci rpc_set_port((struct sockaddr *)&myaddr, port); 180762306a36Sopenharmony_ci err = kernel_bind(sock, (struct sockaddr *)&myaddr, 180862306a36Sopenharmony_ci transport->xprt.addrlen); 180962306a36Sopenharmony_ci if (err == 0) { 181062306a36Sopenharmony_ci if (transport->xprt.reuseport) 181162306a36Sopenharmony_ci transport->srcport = port; 181262306a36Sopenharmony_ci break; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci last = port; 181562306a36Sopenharmony_ci port = xs_next_srcport(transport, port); 181662306a36Sopenharmony_ci if (port > last) 181762306a36Sopenharmony_ci nloop++; 181862306a36Sopenharmony_ci } while (err == -EADDRINUSE && nloop != 2); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci if (myaddr.ss_family == AF_INET) 182162306a36Sopenharmony_ci dprintk("RPC: %s %pI4:%u: %s (%d)\n", __func__, 182262306a36Sopenharmony_ci &((struct sockaddr_in *)&myaddr)->sin_addr, 182362306a36Sopenharmony_ci port, err ? "failed" : "ok", err); 182462306a36Sopenharmony_ci else 182562306a36Sopenharmony_ci dprintk("RPC: %s %pI6:%u: %s (%d)\n", __func__, 182662306a36Sopenharmony_ci &((struct sockaddr_in6 *)&myaddr)->sin6_addr, 182762306a36Sopenharmony_ci port, err ? "failed" : "ok", err); 182862306a36Sopenharmony_ci return err; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci/* 183262306a36Sopenharmony_ci * We don't support autobind on AF_LOCAL sockets 183362306a36Sopenharmony_ci */ 183462306a36Sopenharmony_cistatic void xs_local_rpcbind(struct rpc_task *task) 183562306a36Sopenharmony_ci{ 183662306a36Sopenharmony_ci xprt_set_bound(task->tk_xprt); 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic void xs_local_set_port(struct rpc_xprt *xprt, unsigned short port) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC 184462306a36Sopenharmony_cistatic struct lock_class_key xs_key[3]; 184562306a36Sopenharmony_cistatic struct lock_class_key xs_slock_key[3]; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_cistatic inline void xs_reclassify_socketu(struct socket *sock) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci struct sock *sk = sock->sk; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC", 185262306a36Sopenharmony_ci &xs_slock_key[0], "sk_lock-AF_LOCAL-RPC", &xs_key[0]); 185362306a36Sopenharmony_ci} 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_cistatic inline void xs_reclassify_socket4(struct socket *sock) 185662306a36Sopenharmony_ci{ 185762306a36Sopenharmony_ci struct sock *sk = sock->sk; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC", 186062306a36Sopenharmony_ci &xs_slock_key[1], "sk_lock-AF_INET-RPC", &xs_key[1]); 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_cistatic inline void xs_reclassify_socket6(struct socket *sock) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct sock *sk = sock->sk; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC", 186862306a36Sopenharmony_ci &xs_slock_key[2], "sk_lock-AF_INET6-RPC", &xs_key[2]); 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_cistatic inline void xs_reclassify_socket(int family, struct socket *sock) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci if (WARN_ON_ONCE(!sock_allow_reclassification(sock->sk))) 187462306a36Sopenharmony_ci return; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci switch (family) { 187762306a36Sopenharmony_ci case AF_LOCAL: 187862306a36Sopenharmony_ci xs_reclassify_socketu(sock); 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci case AF_INET: 188162306a36Sopenharmony_ci xs_reclassify_socket4(sock); 188262306a36Sopenharmony_ci break; 188362306a36Sopenharmony_ci case AF_INET6: 188462306a36Sopenharmony_ci xs_reclassify_socket6(sock); 188562306a36Sopenharmony_ci break; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci} 188862306a36Sopenharmony_ci#else 188962306a36Sopenharmony_cistatic inline void xs_reclassify_socket(int family, struct socket *sock) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci} 189262306a36Sopenharmony_ci#endif 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_cistatic void xs_dummy_setup_socket(struct work_struct *work) 189562306a36Sopenharmony_ci{ 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_cistatic struct socket *xs_create_sock(struct rpc_xprt *xprt, 189962306a36Sopenharmony_ci struct sock_xprt *transport, int family, int type, 190062306a36Sopenharmony_ci int protocol, bool reuseport) 190162306a36Sopenharmony_ci{ 190262306a36Sopenharmony_ci struct file *filp; 190362306a36Sopenharmony_ci struct socket *sock; 190462306a36Sopenharmony_ci int err; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci err = __sock_create(xprt->xprt_net, family, type, protocol, &sock, 1); 190762306a36Sopenharmony_ci if (err < 0) { 190862306a36Sopenharmony_ci dprintk("RPC: can't create %d transport socket (%d).\n", 190962306a36Sopenharmony_ci protocol, -err); 191062306a36Sopenharmony_ci goto out; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci xs_reclassify_socket(family, sock); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if (reuseport) 191562306a36Sopenharmony_ci sock_set_reuseport(sock->sk); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci err = xs_bind(transport, sock); 191862306a36Sopenharmony_ci if (err) { 191962306a36Sopenharmony_ci sock_release(sock); 192062306a36Sopenharmony_ci goto out; 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci filp = sock_alloc_file(sock, O_NONBLOCK, NULL); 192462306a36Sopenharmony_ci if (IS_ERR(filp)) 192562306a36Sopenharmony_ci return ERR_CAST(filp); 192662306a36Sopenharmony_ci transport->file = filp; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci return sock; 192962306a36Sopenharmony_ciout: 193062306a36Sopenharmony_ci return ERR_PTR(err); 193162306a36Sopenharmony_ci} 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_cistatic int xs_local_finish_connecting(struct rpc_xprt *xprt, 193462306a36Sopenharmony_ci struct socket *sock) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, 193762306a36Sopenharmony_ci xprt); 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci if (!transport->inet) { 194062306a36Sopenharmony_ci struct sock *sk = sock->sk; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci lock_sock(sk); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci xs_save_old_callbacks(transport, sk); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci sk->sk_user_data = xprt; 194762306a36Sopenharmony_ci sk->sk_data_ready = xs_data_ready; 194862306a36Sopenharmony_ci sk->sk_write_space = xs_udp_write_space; 194962306a36Sopenharmony_ci sk->sk_state_change = xs_local_state_change; 195062306a36Sopenharmony_ci sk->sk_error_report = xs_error_report; 195162306a36Sopenharmony_ci sk->sk_use_task_frag = false; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci xprt_clear_connected(xprt); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci /* Reset to new socket */ 195662306a36Sopenharmony_ci transport->sock = sock; 195762306a36Sopenharmony_ci transport->inet = sk; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci release_sock(sk); 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci xs_stream_start_connect(transport); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, 0); 196562306a36Sopenharmony_ci} 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci/** 196862306a36Sopenharmony_ci * xs_local_setup_socket - create AF_LOCAL socket, connect to a local endpoint 196962306a36Sopenharmony_ci * @transport: socket transport to connect 197062306a36Sopenharmony_ci */ 197162306a36Sopenharmony_cistatic int xs_local_setup_socket(struct sock_xprt *transport) 197262306a36Sopenharmony_ci{ 197362306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 197462306a36Sopenharmony_ci struct file *filp; 197562306a36Sopenharmony_ci struct socket *sock; 197662306a36Sopenharmony_ci int status; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci status = __sock_create(xprt->xprt_net, AF_LOCAL, 197962306a36Sopenharmony_ci SOCK_STREAM, 0, &sock, 1); 198062306a36Sopenharmony_ci if (status < 0) { 198162306a36Sopenharmony_ci dprintk("RPC: can't create AF_LOCAL " 198262306a36Sopenharmony_ci "transport socket (%d).\n", -status); 198362306a36Sopenharmony_ci goto out; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci xs_reclassify_socket(AF_LOCAL, sock); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci filp = sock_alloc_file(sock, O_NONBLOCK, NULL); 198862306a36Sopenharmony_ci if (IS_ERR(filp)) { 198962306a36Sopenharmony_ci status = PTR_ERR(filp); 199062306a36Sopenharmony_ci goto out; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci transport->file = filp; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci dprintk("RPC: worker connecting xprt %p via AF_LOCAL to %s\n", 199562306a36Sopenharmony_ci xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci status = xs_local_finish_connecting(xprt, sock); 199862306a36Sopenharmony_ci trace_rpc_socket_connect(xprt, sock, status); 199962306a36Sopenharmony_ci switch (status) { 200062306a36Sopenharmony_ci case 0: 200162306a36Sopenharmony_ci dprintk("RPC: xprt %p connected to %s\n", 200262306a36Sopenharmony_ci xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); 200362306a36Sopenharmony_ci xprt->stat.connect_count++; 200462306a36Sopenharmony_ci xprt->stat.connect_time += (long)jiffies - 200562306a36Sopenharmony_ci xprt->stat.connect_start; 200662306a36Sopenharmony_ci xprt_set_connected(xprt); 200762306a36Sopenharmony_ci break; 200862306a36Sopenharmony_ci case -ENOBUFS: 200962306a36Sopenharmony_ci break; 201062306a36Sopenharmony_ci case -ENOENT: 201162306a36Sopenharmony_ci dprintk("RPC: xprt %p: socket %s does not exist\n", 201262306a36Sopenharmony_ci xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); 201362306a36Sopenharmony_ci break; 201462306a36Sopenharmony_ci case -ECONNREFUSED: 201562306a36Sopenharmony_ci dprintk("RPC: xprt %p: connection refused for %s\n", 201662306a36Sopenharmony_ci xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); 201762306a36Sopenharmony_ci break; 201862306a36Sopenharmony_ci default: 201962306a36Sopenharmony_ci printk(KERN_ERR "%s: unhandled error (%d) connecting to %s\n", 202062306a36Sopenharmony_ci __func__, -status, 202162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR]); 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ciout: 202562306a36Sopenharmony_ci xprt_clear_connecting(xprt); 202662306a36Sopenharmony_ci xprt_wake_pending_tasks(xprt, status); 202762306a36Sopenharmony_ci return status; 202862306a36Sopenharmony_ci} 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_cistatic void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task) 203162306a36Sopenharmony_ci{ 203262306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 203362306a36Sopenharmony_ci int ret; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (transport->file) 203662306a36Sopenharmony_ci goto force_disconnect; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (RPC_IS_ASYNC(task)) { 203962306a36Sopenharmony_ci /* 204062306a36Sopenharmony_ci * We want the AF_LOCAL connect to be resolved in the 204162306a36Sopenharmony_ci * filesystem namespace of the process making the rpc 204262306a36Sopenharmony_ci * call. Thus we connect synchronously. 204362306a36Sopenharmony_ci * 204462306a36Sopenharmony_ci * If we want to support asynchronous AF_LOCAL calls, 204562306a36Sopenharmony_ci * we'll need to figure out how to pass a namespace to 204662306a36Sopenharmony_ci * connect. 204762306a36Sopenharmony_ci */ 204862306a36Sopenharmony_ci rpc_task_set_rpc_status(task, -ENOTCONN); 204962306a36Sopenharmony_ci goto out_wake; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci ret = xs_local_setup_socket(transport); 205262306a36Sopenharmony_ci if (ret && !RPC_IS_SOFTCONN(task)) 205362306a36Sopenharmony_ci msleep_interruptible(15000); 205462306a36Sopenharmony_ci return; 205562306a36Sopenharmony_ciforce_disconnect: 205662306a36Sopenharmony_ci xprt_force_disconnect(xprt); 205762306a36Sopenharmony_ciout_wake: 205862306a36Sopenharmony_ci xprt_clear_connecting(xprt); 205962306a36Sopenharmony_ci xprt_wake_pending_tasks(xprt, -ENOTCONN); 206062306a36Sopenharmony_ci} 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_SWAP) 206362306a36Sopenharmony_ci/* 206462306a36Sopenharmony_ci * Note that this should be called with XPRT_LOCKED held, or recv_mutex 206562306a36Sopenharmony_ci * held, or when we otherwise know that we have exclusive access to the 206662306a36Sopenharmony_ci * socket, to guard against races with xs_reset_transport. 206762306a36Sopenharmony_ci */ 206862306a36Sopenharmony_cistatic void xs_set_memalloc(struct rpc_xprt *xprt) 206962306a36Sopenharmony_ci{ 207062306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, 207162306a36Sopenharmony_ci xprt); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci /* 207462306a36Sopenharmony_ci * If there's no sock, then we have nothing to set. The 207562306a36Sopenharmony_ci * reconnecting process will get it for us. 207662306a36Sopenharmony_ci */ 207762306a36Sopenharmony_ci if (!transport->inet) 207862306a36Sopenharmony_ci return; 207962306a36Sopenharmony_ci if (atomic_read(&xprt->swapper)) 208062306a36Sopenharmony_ci sk_set_memalloc(transport->inet); 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci/** 208462306a36Sopenharmony_ci * xs_enable_swap - Tag this transport as being used for swap. 208562306a36Sopenharmony_ci * @xprt: transport to tag 208662306a36Sopenharmony_ci * 208762306a36Sopenharmony_ci * Take a reference to this transport on behalf of the rpc_clnt, and 208862306a36Sopenharmony_ci * optionally mark it for swapping if it wasn't already. 208962306a36Sopenharmony_ci */ 209062306a36Sopenharmony_cistatic int 209162306a36Sopenharmony_cixs_enable_swap(struct rpc_xprt *xprt) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci mutex_lock(&xs->recv_mutex); 209662306a36Sopenharmony_ci if (atomic_inc_return(&xprt->swapper) == 1 && 209762306a36Sopenharmony_ci xs->inet) 209862306a36Sopenharmony_ci sk_set_memalloc(xs->inet); 209962306a36Sopenharmony_ci mutex_unlock(&xs->recv_mutex); 210062306a36Sopenharmony_ci return 0; 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci/** 210462306a36Sopenharmony_ci * xs_disable_swap - Untag this transport as being used for swap. 210562306a36Sopenharmony_ci * @xprt: transport to tag 210662306a36Sopenharmony_ci * 210762306a36Sopenharmony_ci * Drop a "swapper" reference to this xprt on behalf of the rpc_clnt. If the 210862306a36Sopenharmony_ci * swapper refcount goes to 0, untag the socket as a memalloc socket. 210962306a36Sopenharmony_ci */ 211062306a36Sopenharmony_cistatic void 211162306a36Sopenharmony_cixs_disable_swap(struct rpc_xprt *xprt) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci mutex_lock(&xs->recv_mutex); 211662306a36Sopenharmony_ci if (atomic_dec_and_test(&xprt->swapper) && 211762306a36Sopenharmony_ci xs->inet) 211862306a36Sopenharmony_ci sk_clear_memalloc(xs->inet); 211962306a36Sopenharmony_ci mutex_unlock(&xs->recv_mutex); 212062306a36Sopenharmony_ci} 212162306a36Sopenharmony_ci#else 212262306a36Sopenharmony_cistatic void xs_set_memalloc(struct rpc_xprt *xprt) 212362306a36Sopenharmony_ci{ 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic int 212762306a36Sopenharmony_cixs_enable_swap(struct rpc_xprt *xprt) 212862306a36Sopenharmony_ci{ 212962306a36Sopenharmony_ci return -EINVAL; 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cistatic void 213362306a36Sopenharmony_cixs_disable_swap(struct rpc_xprt *xprt) 213462306a36Sopenharmony_ci{ 213562306a36Sopenharmony_ci} 213662306a36Sopenharmony_ci#endif 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cistatic void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (!transport->inet) { 214362306a36Sopenharmony_ci struct sock *sk = sock->sk; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci lock_sock(sk); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci xs_save_old_callbacks(transport, sk); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci sk->sk_user_data = xprt; 215062306a36Sopenharmony_ci sk->sk_data_ready = xs_data_ready; 215162306a36Sopenharmony_ci sk->sk_write_space = xs_udp_write_space; 215262306a36Sopenharmony_ci sk->sk_use_task_frag = false; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci xprt_set_connected(xprt); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci /* Reset to new socket */ 215762306a36Sopenharmony_ci transport->sock = sock; 215862306a36Sopenharmony_ci transport->inet = sk; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci xs_set_memalloc(xprt); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci release_sock(sk); 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci xs_udp_do_set_buffer_size(xprt); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci xprt->stat.connect_start = jiffies; 216762306a36Sopenharmony_ci} 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cistatic void xs_udp_setup_socket(struct work_struct *work) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci struct sock_xprt *transport = 217262306a36Sopenharmony_ci container_of(work, struct sock_xprt, connect_worker.work); 217362306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 217462306a36Sopenharmony_ci struct socket *sock; 217562306a36Sopenharmony_ci int status = -EIO; 217662306a36Sopenharmony_ci unsigned int pflags = current->flags; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci if (atomic_read(&xprt->swapper)) 217962306a36Sopenharmony_ci current->flags |= PF_MEMALLOC; 218062306a36Sopenharmony_ci sock = xs_create_sock(xprt, transport, 218162306a36Sopenharmony_ci xs_addr(xprt)->sa_family, SOCK_DGRAM, 218262306a36Sopenharmony_ci IPPROTO_UDP, false); 218362306a36Sopenharmony_ci if (IS_ERR(sock)) 218462306a36Sopenharmony_ci goto out; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci dprintk("RPC: worker connecting xprt %p via %s to " 218762306a36Sopenharmony_ci "%s (port %s)\n", xprt, 218862306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO], 218962306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 219062306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT]); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci xs_udp_finish_connecting(xprt, sock); 219362306a36Sopenharmony_ci trace_rpc_socket_connect(xprt, sock, 0); 219462306a36Sopenharmony_ci status = 0; 219562306a36Sopenharmony_ciout: 219662306a36Sopenharmony_ci xprt_clear_connecting(xprt); 219762306a36Sopenharmony_ci xprt_unlock_connect(xprt, transport); 219862306a36Sopenharmony_ci xprt_wake_pending_tasks(xprt, status); 219962306a36Sopenharmony_ci current_restore_flags(pflags, PF_MEMALLOC); 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci/** 220362306a36Sopenharmony_ci * xs_tcp_shutdown - gracefully shut down a TCP socket 220462306a36Sopenharmony_ci * @xprt: transport 220562306a36Sopenharmony_ci * 220662306a36Sopenharmony_ci * Initiates a graceful shutdown of the TCP socket by calling the 220762306a36Sopenharmony_ci * equivalent of shutdown(SHUT_RDWR); 220862306a36Sopenharmony_ci */ 220962306a36Sopenharmony_cistatic void xs_tcp_shutdown(struct rpc_xprt *xprt) 221062306a36Sopenharmony_ci{ 221162306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 221262306a36Sopenharmony_ci struct socket *sock = transport->sock; 221362306a36Sopenharmony_ci int skst = transport->inet ? transport->inet->sk_state : TCP_CLOSE; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci if (sock == NULL) 221662306a36Sopenharmony_ci return; 221762306a36Sopenharmony_ci if (!xprt->reuseport) { 221862306a36Sopenharmony_ci xs_close(xprt); 221962306a36Sopenharmony_ci return; 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci switch (skst) { 222262306a36Sopenharmony_ci case TCP_FIN_WAIT1: 222362306a36Sopenharmony_ci case TCP_FIN_WAIT2: 222462306a36Sopenharmony_ci case TCP_LAST_ACK: 222562306a36Sopenharmony_ci break; 222662306a36Sopenharmony_ci case TCP_ESTABLISHED: 222762306a36Sopenharmony_ci case TCP_CLOSE_WAIT: 222862306a36Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 222962306a36Sopenharmony_ci trace_rpc_socket_shutdown(xprt, sock); 223062306a36Sopenharmony_ci break; 223162306a36Sopenharmony_ci default: 223262306a36Sopenharmony_ci xs_reset_transport(transport); 223362306a36Sopenharmony_ci } 223462306a36Sopenharmony_ci} 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_cistatic void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, 223762306a36Sopenharmony_ci struct socket *sock) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 224062306a36Sopenharmony_ci struct net *net = sock_net(sock->sk); 224162306a36Sopenharmony_ci unsigned long connect_timeout; 224262306a36Sopenharmony_ci unsigned long syn_retries; 224362306a36Sopenharmony_ci unsigned int keepidle; 224462306a36Sopenharmony_ci unsigned int keepcnt; 224562306a36Sopenharmony_ci unsigned int timeo; 224662306a36Sopenharmony_ci unsigned long t; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci spin_lock(&xprt->transport_lock); 224962306a36Sopenharmony_ci keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ); 225062306a36Sopenharmony_ci keepcnt = xprt->timeout->to_retries + 1; 225162306a36Sopenharmony_ci timeo = jiffies_to_msecs(xprt->timeout->to_initval) * 225262306a36Sopenharmony_ci (xprt->timeout->to_retries + 1); 225362306a36Sopenharmony_ci clear_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state); 225462306a36Sopenharmony_ci spin_unlock(&xprt->transport_lock); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci /* TCP Keepalive options */ 225762306a36Sopenharmony_ci sock_set_keepalive(sock->sk); 225862306a36Sopenharmony_ci tcp_sock_set_keepidle(sock->sk, keepidle); 225962306a36Sopenharmony_ci tcp_sock_set_keepintvl(sock->sk, keepidle); 226062306a36Sopenharmony_ci tcp_sock_set_keepcnt(sock->sk, keepcnt); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci /* TCP user timeout (see RFC5482) */ 226362306a36Sopenharmony_ci tcp_sock_set_user_timeout(sock->sk, timeo); 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci /* Connect timeout */ 226662306a36Sopenharmony_ci connect_timeout = max_t(unsigned long, 226762306a36Sopenharmony_ci DIV_ROUND_UP(xprt->connect_timeout, HZ), 1); 226862306a36Sopenharmony_ci syn_retries = max_t(unsigned long, 226962306a36Sopenharmony_ci READ_ONCE(net->ipv4.sysctl_tcp_syn_retries), 1); 227062306a36Sopenharmony_ci for (t = 0; t <= syn_retries && (1UL << t) < connect_timeout; t++) 227162306a36Sopenharmony_ci ; 227262306a36Sopenharmony_ci if (t <= syn_retries) 227362306a36Sopenharmony_ci tcp_sock_set_syncnt(sock->sk, t - 1); 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_cistatic void xs_tcp_do_set_connect_timeout(struct rpc_xprt *xprt, 227762306a36Sopenharmony_ci unsigned long connect_timeout) 227862306a36Sopenharmony_ci{ 227962306a36Sopenharmony_ci struct sock_xprt *transport = 228062306a36Sopenharmony_ci container_of(xprt, struct sock_xprt, xprt); 228162306a36Sopenharmony_ci struct rpc_timeout to; 228262306a36Sopenharmony_ci unsigned long initval; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci memcpy(&to, xprt->timeout, sizeof(to)); 228562306a36Sopenharmony_ci /* Arbitrary lower limit */ 228662306a36Sopenharmony_ci initval = max_t(unsigned long, connect_timeout, XS_TCP_INIT_REEST_TO); 228762306a36Sopenharmony_ci to.to_initval = initval; 228862306a36Sopenharmony_ci to.to_maxval = initval; 228962306a36Sopenharmony_ci to.to_retries = 0; 229062306a36Sopenharmony_ci memcpy(&transport->tcp_timeout, &to, sizeof(transport->tcp_timeout)); 229162306a36Sopenharmony_ci xprt->timeout = &transport->tcp_timeout; 229262306a36Sopenharmony_ci xprt->connect_timeout = connect_timeout; 229362306a36Sopenharmony_ci} 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_cistatic void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt, 229662306a36Sopenharmony_ci unsigned long connect_timeout, 229762306a36Sopenharmony_ci unsigned long reconnect_timeout) 229862306a36Sopenharmony_ci{ 229962306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci spin_lock(&xprt->transport_lock); 230262306a36Sopenharmony_ci if (reconnect_timeout < xprt->max_reconnect_timeout) 230362306a36Sopenharmony_ci xprt->max_reconnect_timeout = reconnect_timeout; 230462306a36Sopenharmony_ci if (connect_timeout < xprt->connect_timeout) 230562306a36Sopenharmony_ci xs_tcp_do_set_connect_timeout(xprt, connect_timeout); 230662306a36Sopenharmony_ci set_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state); 230762306a36Sopenharmony_ci spin_unlock(&xprt->transport_lock); 230862306a36Sopenharmony_ci} 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_cistatic int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) 231162306a36Sopenharmony_ci{ 231262306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (!transport->inet) { 231562306a36Sopenharmony_ci struct sock *sk = sock->sk; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci /* Avoid temporary address, they are bad for long-lived 231862306a36Sopenharmony_ci * connections such as NFS mounts. 231962306a36Sopenharmony_ci * RFC4941, section 3.6 suggests that: 232062306a36Sopenharmony_ci * Individual applications, which have specific 232162306a36Sopenharmony_ci * knowledge about the normal duration of connections, 232262306a36Sopenharmony_ci * MAY override this as appropriate. 232362306a36Sopenharmony_ci */ 232462306a36Sopenharmony_ci if (xs_addr(xprt)->sa_family == PF_INET6) { 232562306a36Sopenharmony_ci ip6_sock_set_addr_preferences(sk, 232662306a36Sopenharmony_ci IPV6_PREFER_SRC_PUBLIC); 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci xs_tcp_set_socket_timeouts(xprt, sock); 233062306a36Sopenharmony_ci tcp_sock_set_nodelay(sk); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci lock_sock(sk); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci xs_save_old_callbacks(transport, sk); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci sk->sk_user_data = xprt; 233762306a36Sopenharmony_ci sk->sk_data_ready = xs_data_ready; 233862306a36Sopenharmony_ci sk->sk_state_change = xs_tcp_state_change; 233962306a36Sopenharmony_ci sk->sk_write_space = xs_tcp_write_space; 234062306a36Sopenharmony_ci sk->sk_error_report = xs_error_report; 234162306a36Sopenharmony_ci sk->sk_use_task_frag = false; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci /* socket options */ 234462306a36Sopenharmony_ci sock_reset_flag(sk, SOCK_LINGER); 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci xprt_clear_connected(xprt); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci /* Reset to new socket */ 234962306a36Sopenharmony_ci transport->sock = sock; 235062306a36Sopenharmony_ci transport->inet = sk; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci release_sock(sk); 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci if (!xprt_bound(xprt)) 235662306a36Sopenharmony_ci return -ENOTCONN; 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci xs_set_memalloc(xprt); 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci xs_stream_start_connect(transport); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci /* Tell the socket layer to start connecting... */ 236362306a36Sopenharmony_ci set_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); 236462306a36Sopenharmony_ci return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK); 236562306a36Sopenharmony_ci} 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci/** 236862306a36Sopenharmony_ci * xs_tcp_setup_socket - create a TCP socket and connect to a remote endpoint 236962306a36Sopenharmony_ci * @work: queued work item 237062306a36Sopenharmony_ci * 237162306a36Sopenharmony_ci * Invoked by a work queue tasklet. 237262306a36Sopenharmony_ci */ 237362306a36Sopenharmony_cistatic void xs_tcp_setup_socket(struct work_struct *work) 237462306a36Sopenharmony_ci{ 237562306a36Sopenharmony_ci struct sock_xprt *transport = 237662306a36Sopenharmony_ci container_of(work, struct sock_xprt, connect_worker.work); 237762306a36Sopenharmony_ci struct socket *sock = transport->sock; 237862306a36Sopenharmony_ci struct rpc_xprt *xprt = &transport->xprt; 237962306a36Sopenharmony_ci int status; 238062306a36Sopenharmony_ci unsigned int pflags = current->flags; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci if (atomic_read(&xprt->swapper)) 238362306a36Sopenharmony_ci current->flags |= PF_MEMALLOC; 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci if (xprt_connected(xprt)) 238662306a36Sopenharmony_ci goto out; 238762306a36Sopenharmony_ci if (test_and_clear_bit(XPRT_SOCK_CONNECT_SENT, 238862306a36Sopenharmony_ci &transport->sock_state) || 238962306a36Sopenharmony_ci !sock) { 239062306a36Sopenharmony_ci xs_reset_transport(transport); 239162306a36Sopenharmony_ci sock = xs_create_sock(xprt, transport, xs_addr(xprt)->sa_family, 239262306a36Sopenharmony_ci SOCK_STREAM, IPPROTO_TCP, true); 239362306a36Sopenharmony_ci if (IS_ERR(sock)) { 239462306a36Sopenharmony_ci xprt_wake_pending_tasks(xprt, PTR_ERR(sock)); 239562306a36Sopenharmony_ci goto out; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci dprintk("RPC: worker connecting xprt %p via %s to " 240062306a36Sopenharmony_ci "%s (port %s)\n", xprt, 240162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO], 240262306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 240362306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT]); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci status = xs_tcp_finish_connecting(xprt, sock); 240662306a36Sopenharmony_ci trace_rpc_socket_connect(xprt, sock, status); 240762306a36Sopenharmony_ci dprintk("RPC: %p connect status %d connected %d sock state %d\n", 240862306a36Sopenharmony_ci xprt, -status, xprt_connected(xprt), 240962306a36Sopenharmony_ci sock->sk->sk_state); 241062306a36Sopenharmony_ci switch (status) { 241162306a36Sopenharmony_ci case 0: 241262306a36Sopenharmony_ci case -EINPROGRESS: 241362306a36Sopenharmony_ci /* SYN_SENT! */ 241462306a36Sopenharmony_ci set_bit(XPRT_SOCK_CONNECT_SENT, &transport->sock_state); 241562306a36Sopenharmony_ci if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) 241662306a36Sopenharmony_ci xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; 241762306a36Sopenharmony_ci fallthrough; 241862306a36Sopenharmony_ci case -EALREADY: 241962306a36Sopenharmony_ci goto out_unlock; 242062306a36Sopenharmony_ci case -EADDRNOTAVAIL: 242162306a36Sopenharmony_ci /* Source port number is unavailable. Try a new one! */ 242262306a36Sopenharmony_ci transport->srcport = 0; 242362306a36Sopenharmony_ci status = -EAGAIN; 242462306a36Sopenharmony_ci break; 242562306a36Sopenharmony_ci case -EINVAL: 242662306a36Sopenharmony_ci /* Happens, for instance, if the user specified a link 242762306a36Sopenharmony_ci * local IPv6 address without a scope-id. 242862306a36Sopenharmony_ci */ 242962306a36Sopenharmony_ci case -ECONNREFUSED: 243062306a36Sopenharmony_ci case -ECONNRESET: 243162306a36Sopenharmony_ci case -ENETDOWN: 243262306a36Sopenharmony_ci case -ENETUNREACH: 243362306a36Sopenharmony_ci case -EHOSTUNREACH: 243462306a36Sopenharmony_ci case -EADDRINUSE: 243562306a36Sopenharmony_ci case -ENOBUFS: 243662306a36Sopenharmony_ci break; 243762306a36Sopenharmony_ci default: 243862306a36Sopenharmony_ci printk("%s: connect returned unhandled error %d\n", 243962306a36Sopenharmony_ci __func__, status); 244062306a36Sopenharmony_ci status = -EAGAIN; 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* xs_tcp_force_close() wakes tasks with a fixed error code. 244462306a36Sopenharmony_ci * We need to wake them first to ensure the correct error code. 244562306a36Sopenharmony_ci */ 244662306a36Sopenharmony_ci xprt_wake_pending_tasks(xprt, status); 244762306a36Sopenharmony_ci xs_tcp_force_close(xprt); 244862306a36Sopenharmony_ciout: 244962306a36Sopenharmony_ci xprt_clear_connecting(xprt); 245062306a36Sopenharmony_ciout_unlock: 245162306a36Sopenharmony_ci xprt_unlock_connect(xprt, transport); 245262306a36Sopenharmony_ci current_restore_flags(pflags, PF_MEMALLOC); 245362306a36Sopenharmony_ci} 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci/* 245662306a36Sopenharmony_ci * Transfer the connected socket to @upper_transport, then mark that 245762306a36Sopenharmony_ci * xprt CONNECTED. 245862306a36Sopenharmony_ci */ 245962306a36Sopenharmony_cistatic int xs_tcp_tls_finish_connecting(struct rpc_xprt *lower_xprt, 246062306a36Sopenharmony_ci struct sock_xprt *upper_transport) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci struct sock_xprt *lower_transport = 246362306a36Sopenharmony_ci container_of(lower_xprt, struct sock_xprt, xprt); 246462306a36Sopenharmony_ci struct rpc_xprt *upper_xprt = &upper_transport->xprt; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (!upper_transport->inet) { 246762306a36Sopenharmony_ci struct socket *sock = lower_transport->sock; 246862306a36Sopenharmony_ci struct sock *sk = sock->sk; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci /* Avoid temporary address, they are bad for long-lived 247162306a36Sopenharmony_ci * connections such as NFS mounts. 247262306a36Sopenharmony_ci * RFC4941, section 3.6 suggests that: 247362306a36Sopenharmony_ci * Individual applications, which have specific 247462306a36Sopenharmony_ci * knowledge about the normal duration of connections, 247562306a36Sopenharmony_ci * MAY override this as appropriate. 247662306a36Sopenharmony_ci */ 247762306a36Sopenharmony_ci if (xs_addr(upper_xprt)->sa_family == PF_INET6) 247862306a36Sopenharmony_ci ip6_sock_set_addr_preferences(sk, IPV6_PREFER_SRC_PUBLIC); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci xs_tcp_set_socket_timeouts(upper_xprt, sock); 248162306a36Sopenharmony_ci tcp_sock_set_nodelay(sk); 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci lock_sock(sk); 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci /* @sk is already connected, so it now has the RPC callbacks. 248662306a36Sopenharmony_ci * Reach into @lower_transport to save the original ones. 248762306a36Sopenharmony_ci */ 248862306a36Sopenharmony_ci upper_transport->old_data_ready = lower_transport->old_data_ready; 248962306a36Sopenharmony_ci upper_transport->old_state_change = lower_transport->old_state_change; 249062306a36Sopenharmony_ci upper_transport->old_write_space = lower_transport->old_write_space; 249162306a36Sopenharmony_ci upper_transport->old_error_report = lower_transport->old_error_report; 249262306a36Sopenharmony_ci sk->sk_user_data = upper_xprt; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci /* socket options */ 249562306a36Sopenharmony_ci sock_reset_flag(sk, SOCK_LINGER); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci xprt_clear_connected(upper_xprt); 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci upper_transport->sock = sock; 250062306a36Sopenharmony_ci upper_transport->inet = sk; 250162306a36Sopenharmony_ci upper_transport->file = lower_transport->file; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci release_sock(sk); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci /* Reset lower_transport before shutting down its clnt */ 250662306a36Sopenharmony_ci mutex_lock(&lower_transport->recv_mutex); 250762306a36Sopenharmony_ci lower_transport->inet = NULL; 250862306a36Sopenharmony_ci lower_transport->sock = NULL; 250962306a36Sopenharmony_ci lower_transport->file = NULL; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci xprt_clear_connected(lower_xprt); 251262306a36Sopenharmony_ci xs_sock_reset_connection_flags(lower_xprt); 251362306a36Sopenharmony_ci xs_stream_reset_connect(lower_transport); 251462306a36Sopenharmony_ci mutex_unlock(&lower_transport->recv_mutex); 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (!xprt_bound(upper_xprt)) 251862306a36Sopenharmony_ci return -ENOTCONN; 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci xs_set_memalloc(upper_xprt); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci if (!xprt_test_and_set_connected(upper_xprt)) { 252362306a36Sopenharmony_ci upper_xprt->connect_cookie++; 252462306a36Sopenharmony_ci clear_bit(XPRT_SOCK_CONNECTING, &upper_transport->sock_state); 252562306a36Sopenharmony_ci xprt_clear_connecting(upper_xprt); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci upper_xprt->stat.connect_count++; 252862306a36Sopenharmony_ci upper_xprt->stat.connect_time += (long)jiffies - 252962306a36Sopenharmony_ci upper_xprt->stat.connect_start; 253062306a36Sopenharmony_ci xs_run_error_worker(upper_transport, XPRT_SOCK_WAKE_PENDING); 253162306a36Sopenharmony_ci } 253262306a36Sopenharmony_ci return 0; 253362306a36Sopenharmony_ci} 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci/** 253662306a36Sopenharmony_ci * xs_tls_handshake_done - TLS handshake completion handler 253762306a36Sopenharmony_ci * @data: address of xprt to wake 253862306a36Sopenharmony_ci * @status: status of handshake 253962306a36Sopenharmony_ci * @peerid: serial number of key containing the remote's identity 254062306a36Sopenharmony_ci * 254162306a36Sopenharmony_ci */ 254262306a36Sopenharmony_cistatic void xs_tls_handshake_done(void *data, int status, key_serial_t peerid) 254362306a36Sopenharmony_ci{ 254462306a36Sopenharmony_ci struct rpc_xprt *lower_xprt = data; 254562306a36Sopenharmony_ci struct sock_xprt *lower_transport = 254662306a36Sopenharmony_ci container_of(lower_xprt, struct sock_xprt, xprt); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci lower_transport->xprt_err = status ? -EACCES : 0; 254962306a36Sopenharmony_ci complete(&lower_transport->handshake_done); 255062306a36Sopenharmony_ci xprt_put(lower_xprt); 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_cistatic int xs_tls_handshake_sync(struct rpc_xprt *lower_xprt, struct xprtsec_parms *xprtsec) 255462306a36Sopenharmony_ci{ 255562306a36Sopenharmony_ci struct sock_xprt *lower_transport = 255662306a36Sopenharmony_ci container_of(lower_xprt, struct sock_xprt, xprt); 255762306a36Sopenharmony_ci struct tls_handshake_args args = { 255862306a36Sopenharmony_ci .ta_sock = lower_transport->sock, 255962306a36Sopenharmony_ci .ta_done = xs_tls_handshake_done, 256062306a36Sopenharmony_ci .ta_data = xprt_get(lower_xprt), 256162306a36Sopenharmony_ci .ta_peername = lower_xprt->servername, 256262306a36Sopenharmony_ci }; 256362306a36Sopenharmony_ci struct sock *sk = lower_transport->inet; 256462306a36Sopenharmony_ci int rc; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci init_completion(&lower_transport->handshake_done); 256762306a36Sopenharmony_ci set_bit(XPRT_SOCK_IGNORE_RECV, &lower_transport->sock_state); 256862306a36Sopenharmony_ci lower_transport->xprt_err = -ETIMEDOUT; 256962306a36Sopenharmony_ci switch (xprtsec->policy) { 257062306a36Sopenharmony_ci case RPC_XPRTSEC_TLS_ANON: 257162306a36Sopenharmony_ci rc = tls_client_hello_anon(&args, GFP_KERNEL); 257262306a36Sopenharmony_ci if (rc) 257362306a36Sopenharmony_ci goto out_put_xprt; 257462306a36Sopenharmony_ci break; 257562306a36Sopenharmony_ci case RPC_XPRTSEC_TLS_X509: 257662306a36Sopenharmony_ci args.ta_my_cert = xprtsec->cert_serial; 257762306a36Sopenharmony_ci args.ta_my_privkey = xprtsec->privkey_serial; 257862306a36Sopenharmony_ci rc = tls_client_hello_x509(&args, GFP_KERNEL); 257962306a36Sopenharmony_ci if (rc) 258062306a36Sopenharmony_ci goto out_put_xprt; 258162306a36Sopenharmony_ci break; 258262306a36Sopenharmony_ci default: 258362306a36Sopenharmony_ci rc = -EACCES; 258462306a36Sopenharmony_ci goto out_put_xprt; 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci rc = wait_for_completion_interruptible_timeout(&lower_transport->handshake_done, 258862306a36Sopenharmony_ci XS_TLS_HANDSHAKE_TO); 258962306a36Sopenharmony_ci if (rc <= 0) { 259062306a36Sopenharmony_ci if (!tls_handshake_cancel(sk)) { 259162306a36Sopenharmony_ci if (rc == 0) 259262306a36Sopenharmony_ci rc = -ETIMEDOUT; 259362306a36Sopenharmony_ci goto out_put_xprt; 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci rc = lower_transport->xprt_err; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ciout: 260062306a36Sopenharmony_ci xs_stream_reset_connect(lower_transport); 260162306a36Sopenharmony_ci clear_bit(XPRT_SOCK_IGNORE_RECV, &lower_transport->sock_state); 260262306a36Sopenharmony_ci return rc; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ciout_put_xprt: 260562306a36Sopenharmony_ci xprt_put(lower_xprt); 260662306a36Sopenharmony_ci goto out; 260762306a36Sopenharmony_ci} 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci/** 261062306a36Sopenharmony_ci * xs_tcp_tls_setup_socket - establish a TLS session on a TCP socket 261162306a36Sopenharmony_ci * @work: queued work item 261262306a36Sopenharmony_ci * 261362306a36Sopenharmony_ci * Invoked by a work queue tasklet. 261462306a36Sopenharmony_ci * 261562306a36Sopenharmony_ci * For RPC-with-TLS, there is a two-stage connection process. 261662306a36Sopenharmony_ci * 261762306a36Sopenharmony_ci * The "upper-layer xprt" is visible to the RPC consumer. Once it has 261862306a36Sopenharmony_ci * been marked connected, the consumer knows that a TCP connection and 261962306a36Sopenharmony_ci * a TLS session have been established. 262062306a36Sopenharmony_ci * 262162306a36Sopenharmony_ci * A "lower-layer xprt", created in this function, handles the mechanics 262262306a36Sopenharmony_ci * of connecting the TCP socket, performing the RPC_AUTH_TLS probe, and 262362306a36Sopenharmony_ci * then driving the TLS handshake. Once all that is complete, the upper 262462306a36Sopenharmony_ci * layer xprt is marked connected. 262562306a36Sopenharmony_ci */ 262662306a36Sopenharmony_cistatic void xs_tcp_tls_setup_socket(struct work_struct *work) 262762306a36Sopenharmony_ci{ 262862306a36Sopenharmony_ci struct sock_xprt *upper_transport = 262962306a36Sopenharmony_ci container_of(work, struct sock_xprt, connect_worker.work); 263062306a36Sopenharmony_ci struct rpc_clnt *upper_clnt = upper_transport->clnt; 263162306a36Sopenharmony_ci struct rpc_xprt *upper_xprt = &upper_transport->xprt; 263262306a36Sopenharmony_ci struct rpc_create_args args = { 263362306a36Sopenharmony_ci .net = upper_xprt->xprt_net, 263462306a36Sopenharmony_ci .protocol = upper_xprt->prot, 263562306a36Sopenharmony_ci .address = (struct sockaddr *)&upper_xprt->addr, 263662306a36Sopenharmony_ci .addrsize = upper_xprt->addrlen, 263762306a36Sopenharmony_ci .timeout = upper_clnt->cl_timeout, 263862306a36Sopenharmony_ci .servername = upper_xprt->servername, 263962306a36Sopenharmony_ci .program = upper_clnt->cl_program, 264062306a36Sopenharmony_ci .prognumber = upper_clnt->cl_prog, 264162306a36Sopenharmony_ci .version = upper_clnt->cl_vers, 264262306a36Sopenharmony_ci .authflavor = RPC_AUTH_TLS, 264362306a36Sopenharmony_ci .cred = upper_clnt->cl_cred, 264462306a36Sopenharmony_ci .xprtsec = { 264562306a36Sopenharmony_ci .policy = RPC_XPRTSEC_NONE, 264662306a36Sopenharmony_ci }, 264762306a36Sopenharmony_ci }; 264862306a36Sopenharmony_ci unsigned int pflags = current->flags; 264962306a36Sopenharmony_ci struct rpc_clnt *lower_clnt; 265062306a36Sopenharmony_ci struct rpc_xprt *lower_xprt; 265162306a36Sopenharmony_ci int status; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (atomic_read(&upper_xprt->swapper)) 265462306a36Sopenharmony_ci current->flags |= PF_MEMALLOC; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci xs_stream_start_connect(upper_transport); 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci /* This implicitly sends an RPC_AUTH_TLS probe */ 265962306a36Sopenharmony_ci lower_clnt = rpc_create(&args); 266062306a36Sopenharmony_ci if (IS_ERR(lower_clnt)) { 266162306a36Sopenharmony_ci trace_rpc_tls_unavailable(upper_clnt, upper_xprt); 266262306a36Sopenharmony_ci clear_bit(XPRT_SOCK_CONNECTING, &upper_transport->sock_state); 266362306a36Sopenharmony_ci xprt_clear_connecting(upper_xprt); 266462306a36Sopenharmony_ci xprt_wake_pending_tasks(upper_xprt, PTR_ERR(lower_clnt)); 266562306a36Sopenharmony_ci xs_run_error_worker(upper_transport, XPRT_SOCK_WAKE_PENDING); 266662306a36Sopenharmony_ci goto out_unlock; 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci /* RPC_AUTH_TLS probe was successful. Try a TLS handshake on 267062306a36Sopenharmony_ci * the lower xprt. 267162306a36Sopenharmony_ci */ 267262306a36Sopenharmony_ci rcu_read_lock(); 267362306a36Sopenharmony_ci lower_xprt = rcu_dereference(lower_clnt->cl_xprt); 267462306a36Sopenharmony_ci rcu_read_unlock(); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (wait_on_bit_lock(&lower_xprt->state, XPRT_LOCKED, TASK_KILLABLE)) 267762306a36Sopenharmony_ci goto out_unlock; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci status = xs_tls_handshake_sync(lower_xprt, &upper_xprt->xprtsec); 268062306a36Sopenharmony_ci if (status) { 268162306a36Sopenharmony_ci trace_rpc_tls_not_started(upper_clnt, upper_xprt); 268262306a36Sopenharmony_ci goto out_close; 268362306a36Sopenharmony_ci } 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci status = xs_tcp_tls_finish_connecting(lower_xprt, upper_transport); 268662306a36Sopenharmony_ci if (status) 268762306a36Sopenharmony_ci goto out_close; 268862306a36Sopenharmony_ci xprt_release_write(lower_xprt, NULL); 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci trace_rpc_socket_connect(upper_xprt, upper_transport->sock, 0); 269162306a36Sopenharmony_ci if (!xprt_test_and_set_connected(upper_xprt)) { 269262306a36Sopenharmony_ci upper_xprt->connect_cookie++; 269362306a36Sopenharmony_ci clear_bit(XPRT_SOCK_CONNECTING, &upper_transport->sock_state); 269462306a36Sopenharmony_ci xprt_clear_connecting(upper_xprt); 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci upper_xprt->stat.connect_count++; 269762306a36Sopenharmony_ci upper_xprt->stat.connect_time += (long)jiffies - 269862306a36Sopenharmony_ci upper_xprt->stat.connect_start; 269962306a36Sopenharmony_ci xs_run_error_worker(upper_transport, XPRT_SOCK_WAKE_PENDING); 270062306a36Sopenharmony_ci } 270162306a36Sopenharmony_ci rpc_shutdown_client(lower_clnt); 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ciout_unlock: 270462306a36Sopenharmony_ci current_restore_flags(pflags, PF_MEMALLOC); 270562306a36Sopenharmony_ci upper_transport->clnt = NULL; 270662306a36Sopenharmony_ci xprt_unlock_connect(upper_xprt, upper_transport); 270762306a36Sopenharmony_ci return; 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ciout_close: 271062306a36Sopenharmony_ci xprt_release_write(lower_xprt, NULL); 271162306a36Sopenharmony_ci rpc_shutdown_client(lower_clnt); 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci /* xprt_force_disconnect() wakes tasks with a fixed tk_status code. 271462306a36Sopenharmony_ci * Wake them first here to ensure they get our tk_status code. 271562306a36Sopenharmony_ci */ 271662306a36Sopenharmony_ci xprt_wake_pending_tasks(upper_xprt, status); 271762306a36Sopenharmony_ci xs_tcp_force_close(upper_xprt); 271862306a36Sopenharmony_ci xprt_clear_connecting(upper_xprt); 271962306a36Sopenharmony_ci goto out_unlock; 272062306a36Sopenharmony_ci} 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci/** 272362306a36Sopenharmony_ci * xs_connect - connect a socket to a remote endpoint 272462306a36Sopenharmony_ci * @xprt: pointer to transport structure 272562306a36Sopenharmony_ci * @task: address of RPC task that manages state of connect request 272662306a36Sopenharmony_ci * 272762306a36Sopenharmony_ci * TCP: If the remote end dropped the connection, delay reconnecting. 272862306a36Sopenharmony_ci * 272962306a36Sopenharmony_ci * UDP socket connects are synchronous, but we use a work queue anyway 273062306a36Sopenharmony_ci * to guarantee that even unprivileged user processes can set up a 273162306a36Sopenharmony_ci * socket on a privileged port. 273262306a36Sopenharmony_ci * 273362306a36Sopenharmony_ci * If a UDP socket connect fails, the delay behavior here prevents 273462306a36Sopenharmony_ci * retry floods (hard mounts). 273562306a36Sopenharmony_ci */ 273662306a36Sopenharmony_cistatic void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task) 273762306a36Sopenharmony_ci{ 273862306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 273962306a36Sopenharmony_ci unsigned long delay = 0; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport)); 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci if (transport->sock != NULL) { 274462306a36Sopenharmony_ci dprintk("RPC: xs_connect delayed xprt %p for %lu " 274562306a36Sopenharmony_ci "seconds\n", xprt, xprt->reestablish_timeout / HZ); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci delay = xprt_reconnect_delay(xprt); 274862306a36Sopenharmony_ci xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci } else 275162306a36Sopenharmony_ci dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci transport->clnt = task->tk_client; 275462306a36Sopenharmony_ci queue_delayed_work(xprtiod_workqueue, 275562306a36Sopenharmony_ci &transport->connect_worker, 275662306a36Sopenharmony_ci delay); 275762306a36Sopenharmony_ci} 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_cistatic void xs_wake_disconnect(struct sock_xprt *transport) 276062306a36Sopenharmony_ci{ 276162306a36Sopenharmony_ci if (test_and_clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state)) 276262306a36Sopenharmony_ci xs_tcp_force_close(&transport->xprt); 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic void xs_wake_write(struct sock_xprt *transport) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci if (test_and_clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state)) 276862306a36Sopenharmony_ci xprt_write_space(&transport->xprt); 276962306a36Sopenharmony_ci} 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_cistatic void xs_wake_error(struct sock_xprt *transport) 277262306a36Sopenharmony_ci{ 277362306a36Sopenharmony_ci int sockerr; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci if (!test_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state)) 277662306a36Sopenharmony_ci return; 277762306a36Sopenharmony_ci mutex_lock(&transport->recv_mutex); 277862306a36Sopenharmony_ci if (transport->sock == NULL) 277962306a36Sopenharmony_ci goto out; 278062306a36Sopenharmony_ci if (!test_and_clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state)) 278162306a36Sopenharmony_ci goto out; 278262306a36Sopenharmony_ci sockerr = xchg(&transport->xprt_err, 0); 278362306a36Sopenharmony_ci if (sockerr < 0) 278462306a36Sopenharmony_ci xprt_wake_pending_tasks(&transport->xprt, sockerr); 278562306a36Sopenharmony_ciout: 278662306a36Sopenharmony_ci mutex_unlock(&transport->recv_mutex); 278762306a36Sopenharmony_ci} 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_cistatic void xs_wake_pending(struct sock_xprt *transport) 279062306a36Sopenharmony_ci{ 279162306a36Sopenharmony_ci if (test_and_clear_bit(XPRT_SOCK_WAKE_PENDING, &transport->sock_state)) 279262306a36Sopenharmony_ci xprt_wake_pending_tasks(&transport->xprt, -EAGAIN); 279362306a36Sopenharmony_ci} 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_cistatic void xs_error_handle(struct work_struct *work) 279662306a36Sopenharmony_ci{ 279762306a36Sopenharmony_ci struct sock_xprt *transport = container_of(work, 279862306a36Sopenharmony_ci struct sock_xprt, error_worker); 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci xs_wake_disconnect(transport); 280162306a36Sopenharmony_ci xs_wake_write(transport); 280262306a36Sopenharmony_ci xs_wake_error(transport); 280362306a36Sopenharmony_ci xs_wake_pending(transport); 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci/** 280762306a36Sopenharmony_ci * xs_local_print_stats - display AF_LOCAL socket-specific stats 280862306a36Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics 280962306a36Sopenharmony_ci * @seq: output file 281062306a36Sopenharmony_ci * 281162306a36Sopenharmony_ci */ 281262306a36Sopenharmony_cistatic void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) 281362306a36Sopenharmony_ci{ 281462306a36Sopenharmony_ci long idle_time = 0; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci if (xprt_connected(xprt)) 281762306a36Sopenharmony_ci idle_time = (long)(jiffies - xprt->last_used) / HZ; 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu " 282062306a36Sopenharmony_ci "%llu %llu %lu %llu %llu\n", 282162306a36Sopenharmony_ci xprt->stat.bind_count, 282262306a36Sopenharmony_ci xprt->stat.connect_count, 282362306a36Sopenharmony_ci xprt->stat.connect_time / HZ, 282462306a36Sopenharmony_ci idle_time, 282562306a36Sopenharmony_ci xprt->stat.sends, 282662306a36Sopenharmony_ci xprt->stat.recvs, 282762306a36Sopenharmony_ci xprt->stat.bad_xids, 282862306a36Sopenharmony_ci xprt->stat.req_u, 282962306a36Sopenharmony_ci xprt->stat.bklog_u, 283062306a36Sopenharmony_ci xprt->stat.max_slots, 283162306a36Sopenharmony_ci xprt->stat.sending_u, 283262306a36Sopenharmony_ci xprt->stat.pending_u); 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci/** 283662306a36Sopenharmony_ci * xs_udp_print_stats - display UDP socket-specific stats 283762306a36Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics 283862306a36Sopenharmony_ci * @seq: output file 283962306a36Sopenharmony_ci * 284062306a36Sopenharmony_ci */ 284162306a36Sopenharmony_cistatic void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) 284262306a36Sopenharmony_ci{ 284362306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu " 284662306a36Sopenharmony_ci "%lu %llu %llu\n", 284762306a36Sopenharmony_ci transport->srcport, 284862306a36Sopenharmony_ci xprt->stat.bind_count, 284962306a36Sopenharmony_ci xprt->stat.sends, 285062306a36Sopenharmony_ci xprt->stat.recvs, 285162306a36Sopenharmony_ci xprt->stat.bad_xids, 285262306a36Sopenharmony_ci xprt->stat.req_u, 285362306a36Sopenharmony_ci xprt->stat.bklog_u, 285462306a36Sopenharmony_ci xprt->stat.max_slots, 285562306a36Sopenharmony_ci xprt->stat.sending_u, 285662306a36Sopenharmony_ci xprt->stat.pending_u); 285762306a36Sopenharmony_ci} 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci/** 286062306a36Sopenharmony_ci * xs_tcp_print_stats - display TCP socket-specific stats 286162306a36Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics 286262306a36Sopenharmony_ci * @seq: output file 286362306a36Sopenharmony_ci * 286462306a36Sopenharmony_ci */ 286562306a36Sopenharmony_cistatic void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) 286662306a36Sopenharmony_ci{ 286762306a36Sopenharmony_ci struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 286862306a36Sopenharmony_ci long idle_time = 0; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci if (xprt_connected(xprt)) 287162306a36Sopenharmony_ci idle_time = (long)(jiffies - xprt->last_used) / HZ; 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu " 287462306a36Sopenharmony_ci "%llu %llu %lu %llu %llu\n", 287562306a36Sopenharmony_ci transport->srcport, 287662306a36Sopenharmony_ci xprt->stat.bind_count, 287762306a36Sopenharmony_ci xprt->stat.connect_count, 287862306a36Sopenharmony_ci xprt->stat.connect_time / HZ, 287962306a36Sopenharmony_ci idle_time, 288062306a36Sopenharmony_ci xprt->stat.sends, 288162306a36Sopenharmony_ci xprt->stat.recvs, 288262306a36Sopenharmony_ci xprt->stat.bad_xids, 288362306a36Sopenharmony_ci xprt->stat.req_u, 288462306a36Sopenharmony_ci xprt->stat.bklog_u, 288562306a36Sopenharmony_ci xprt->stat.max_slots, 288662306a36Sopenharmony_ci xprt->stat.sending_u, 288762306a36Sopenharmony_ci xprt->stat.pending_u); 288862306a36Sopenharmony_ci} 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci/* 289162306a36Sopenharmony_ci * Allocate a bunch of pages for a scratch buffer for the rpc code. The reason 289262306a36Sopenharmony_ci * we allocate pages instead doing a kmalloc like rpc_malloc is because we want 289362306a36Sopenharmony_ci * to use the server side send routines. 289462306a36Sopenharmony_ci */ 289562306a36Sopenharmony_cistatic int bc_malloc(struct rpc_task *task) 289662306a36Sopenharmony_ci{ 289762306a36Sopenharmony_ci struct rpc_rqst *rqst = task->tk_rqstp; 289862306a36Sopenharmony_ci size_t size = rqst->rq_callsize; 289962306a36Sopenharmony_ci struct page *page; 290062306a36Sopenharmony_ci struct rpc_buffer *buf; 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (size > PAGE_SIZE - sizeof(struct rpc_buffer)) { 290362306a36Sopenharmony_ci WARN_ONCE(1, "xprtsock: large bc buffer request (size %zu)\n", 290462306a36Sopenharmony_ci size); 290562306a36Sopenharmony_ci return -EINVAL; 290662306a36Sopenharmony_ci } 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci page = alloc_page(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); 290962306a36Sopenharmony_ci if (!page) 291062306a36Sopenharmony_ci return -ENOMEM; 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci buf = page_address(page); 291362306a36Sopenharmony_ci buf->len = PAGE_SIZE; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci rqst->rq_buffer = buf->data; 291662306a36Sopenharmony_ci rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize; 291762306a36Sopenharmony_ci return 0; 291862306a36Sopenharmony_ci} 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci/* 292162306a36Sopenharmony_ci * Free the space allocated in the bc_alloc routine 292262306a36Sopenharmony_ci */ 292362306a36Sopenharmony_cistatic void bc_free(struct rpc_task *task) 292462306a36Sopenharmony_ci{ 292562306a36Sopenharmony_ci void *buffer = task->tk_rqstp->rq_buffer; 292662306a36Sopenharmony_ci struct rpc_buffer *buf; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci buf = container_of(buffer, struct rpc_buffer, data); 292962306a36Sopenharmony_ci free_page((unsigned long)buf); 293062306a36Sopenharmony_ci} 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_cistatic int bc_sendto(struct rpc_rqst *req) 293362306a36Sopenharmony_ci{ 293462306a36Sopenharmony_ci struct xdr_buf *xdr = &req->rq_snd_buf; 293562306a36Sopenharmony_ci struct sock_xprt *transport = 293662306a36Sopenharmony_ci container_of(req->rq_xprt, struct sock_xprt, xprt); 293762306a36Sopenharmony_ci struct msghdr msg = { 293862306a36Sopenharmony_ci .msg_flags = 0, 293962306a36Sopenharmony_ci }; 294062306a36Sopenharmony_ci rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | 294162306a36Sopenharmony_ci (u32)xdr->len); 294262306a36Sopenharmony_ci unsigned int sent = 0; 294362306a36Sopenharmony_ci int err; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci req->rq_xtime = ktime_get(); 294662306a36Sopenharmony_ci err = xdr_alloc_bvec(xdr, rpc_task_gfp_mask()); 294762306a36Sopenharmony_ci if (err < 0) 294862306a36Sopenharmony_ci return err; 294962306a36Sopenharmony_ci err = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, marker, &sent); 295062306a36Sopenharmony_ci xdr_free_bvec(xdr); 295162306a36Sopenharmony_ci if (err < 0 || sent != (xdr->len + sizeof(marker))) 295262306a36Sopenharmony_ci return -EAGAIN; 295362306a36Sopenharmony_ci return sent; 295462306a36Sopenharmony_ci} 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci/** 295762306a36Sopenharmony_ci * bc_send_request - Send a backchannel Call on a TCP socket 295862306a36Sopenharmony_ci * @req: rpc_rqst containing Call message to be sent 295962306a36Sopenharmony_ci * 296062306a36Sopenharmony_ci * xpt_mutex ensures @rqstp's whole message is written to the socket 296162306a36Sopenharmony_ci * without interruption. 296262306a36Sopenharmony_ci * 296362306a36Sopenharmony_ci * Return values: 296462306a36Sopenharmony_ci * %0 if the message was sent successfully 296562306a36Sopenharmony_ci * %ENOTCONN if the message was not sent 296662306a36Sopenharmony_ci */ 296762306a36Sopenharmony_cistatic int bc_send_request(struct rpc_rqst *req) 296862306a36Sopenharmony_ci{ 296962306a36Sopenharmony_ci struct svc_xprt *xprt; 297062306a36Sopenharmony_ci int len; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci /* 297362306a36Sopenharmony_ci * Get the server socket associated with this callback xprt 297462306a36Sopenharmony_ci */ 297562306a36Sopenharmony_ci xprt = req->rq_xprt->bc_xprt; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci /* 297862306a36Sopenharmony_ci * Grab the mutex to serialize data as the connection is shared 297962306a36Sopenharmony_ci * with the fore channel 298062306a36Sopenharmony_ci */ 298162306a36Sopenharmony_ci mutex_lock(&xprt->xpt_mutex); 298262306a36Sopenharmony_ci if (test_bit(XPT_DEAD, &xprt->xpt_flags)) 298362306a36Sopenharmony_ci len = -ENOTCONN; 298462306a36Sopenharmony_ci else 298562306a36Sopenharmony_ci len = bc_sendto(req); 298662306a36Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci if (len > 0) 298962306a36Sopenharmony_ci len = 0; 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci return len; 299262306a36Sopenharmony_ci} 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci/* 299562306a36Sopenharmony_ci * The close routine. Since this is client initiated, we do nothing 299662306a36Sopenharmony_ci */ 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_cistatic void bc_close(struct rpc_xprt *xprt) 299962306a36Sopenharmony_ci{ 300062306a36Sopenharmony_ci xprt_disconnect_done(xprt); 300162306a36Sopenharmony_ci} 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci/* 300462306a36Sopenharmony_ci * The xprt destroy routine. Again, because this connection is client 300562306a36Sopenharmony_ci * initiated, we do nothing 300662306a36Sopenharmony_ci */ 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_cistatic void bc_destroy(struct rpc_xprt *xprt) 300962306a36Sopenharmony_ci{ 301062306a36Sopenharmony_ci dprintk("RPC: bc_destroy xprt %p\n", xprt); 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci xs_xprt_free(xprt); 301362306a36Sopenharmony_ci module_put(THIS_MODULE); 301462306a36Sopenharmony_ci} 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_cistatic const struct rpc_xprt_ops xs_local_ops = { 301762306a36Sopenharmony_ci .reserve_xprt = xprt_reserve_xprt, 301862306a36Sopenharmony_ci .release_xprt = xprt_release_xprt, 301962306a36Sopenharmony_ci .alloc_slot = xprt_alloc_slot, 302062306a36Sopenharmony_ci .free_slot = xprt_free_slot, 302162306a36Sopenharmony_ci .rpcbind = xs_local_rpcbind, 302262306a36Sopenharmony_ci .set_port = xs_local_set_port, 302362306a36Sopenharmony_ci .connect = xs_local_connect, 302462306a36Sopenharmony_ci .buf_alloc = rpc_malloc, 302562306a36Sopenharmony_ci .buf_free = rpc_free, 302662306a36Sopenharmony_ci .prepare_request = xs_stream_prepare_request, 302762306a36Sopenharmony_ci .send_request = xs_local_send_request, 302862306a36Sopenharmony_ci .wait_for_reply_request = xprt_wait_for_reply_request_def, 302962306a36Sopenharmony_ci .close = xs_close, 303062306a36Sopenharmony_ci .destroy = xs_destroy, 303162306a36Sopenharmony_ci .print_stats = xs_local_print_stats, 303262306a36Sopenharmony_ci .enable_swap = xs_enable_swap, 303362306a36Sopenharmony_ci .disable_swap = xs_disable_swap, 303462306a36Sopenharmony_ci}; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_cistatic const struct rpc_xprt_ops xs_udp_ops = { 303762306a36Sopenharmony_ci .set_buffer_size = xs_udp_set_buffer_size, 303862306a36Sopenharmony_ci .reserve_xprt = xprt_reserve_xprt_cong, 303962306a36Sopenharmony_ci .release_xprt = xprt_release_xprt_cong, 304062306a36Sopenharmony_ci .alloc_slot = xprt_alloc_slot, 304162306a36Sopenharmony_ci .free_slot = xprt_free_slot, 304262306a36Sopenharmony_ci .rpcbind = rpcb_getport_async, 304362306a36Sopenharmony_ci .set_port = xs_set_port, 304462306a36Sopenharmony_ci .connect = xs_connect, 304562306a36Sopenharmony_ci .get_srcaddr = xs_sock_srcaddr, 304662306a36Sopenharmony_ci .get_srcport = xs_sock_srcport, 304762306a36Sopenharmony_ci .buf_alloc = rpc_malloc, 304862306a36Sopenharmony_ci .buf_free = rpc_free, 304962306a36Sopenharmony_ci .send_request = xs_udp_send_request, 305062306a36Sopenharmony_ci .wait_for_reply_request = xprt_wait_for_reply_request_rtt, 305162306a36Sopenharmony_ci .timer = xs_udp_timer, 305262306a36Sopenharmony_ci .release_request = xprt_release_rqst_cong, 305362306a36Sopenharmony_ci .close = xs_close, 305462306a36Sopenharmony_ci .destroy = xs_destroy, 305562306a36Sopenharmony_ci .print_stats = xs_udp_print_stats, 305662306a36Sopenharmony_ci .enable_swap = xs_enable_swap, 305762306a36Sopenharmony_ci .disable_swap = xs_disable_swap, 305862306a36Sopenharmony_ci .inject_disconnect = xs_inject_disconnect, 305962306a36Sopenharmony_ci}; 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_cistatic const struct rpc_xprt_ops xs_tcp_ops = { 306262306a36Sopenharmony_ci .reserve_xprt = xprt_reserve_xprt, 306362306a36Sopenharmony_ci .release_xprt = xprt_release_xprt, 306462306a36Sopenharmony_ci .alloc_slot = xprt_alloc_slot, 306562306a36Sopenharmony_ci .free_slot = xprt_free_slot, 306662306a36Sopenharmony_ci .rpcbind = rpcb_getport_async, 306762306a36Sopenharmony_ci .set_port = xs_set_port, 306862306a36Sopenharmony_ci .connect = xs_connect, 306962306a36Sopenharmony_ci .get_srcaddr = xs_sock_srcaddr, 307062306a36Sopenharmony_ci .get_srcport = xs_sock_srcport, 307162306a36Sopenharmony_ci .buf_alloc = rpc_malloc, 307262306a36Sopenharmony_ci .buf_free = rpc_free, 307362306a36Sopenharmony_ci .prepare_request = xs_stream_prepare_request, 307462306a36Sopenharmony_ci .send_request = xs_tcp_send_request, 307562306a36Sopenharmony_ci .wait_for_reply_request = xprt_wait_for_reply_request_def, 307662306a36Sopenharmony_ci .close = xs_tcp_shutdown, 307762306a36Sopenharmony_ci .destroy = xs_destroy, 307862306a36Sopenharmony_ci .set_connect_timeout = xs_tcp_set_connect_timeout, 307962306a36Sopenharmony_ci .print_stats = xs_tcp_print_stats, 308062306a36Sopenharmony_ci .enable_swap = xs_enable_swap, 308162306a36Sopenharmony_ci .disable_swap = xs_disable_swap, 308262306a36Sopenharmony_ci .inject_disconnect = xs_inject_disconnect, 308362306a36Sopenharmony_ci#ifdef CONFIG_SUNRPC_BACKCHANNEL 308462306a36Sopenharmony_ci .bc_setup = xprt_setup_bc, 308562306a36Sopenharmony_ci .bc_maxpayload = xs_tcp_bc_maxpayload, 308662306a36Sopenharmony_ci .bc_num_slots = xprt_bc_max_slots, 308762306a36Sopenharmony_ci .bc_free_rqst = xprt_free_bc_rqst, 308862306a36Sopenharmony_ci .bc_destroy = xprt_destroy_bc, 308962306a36Sopenharmony_ci#endif 309062306a36Sopenharmony_ci}; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci/* 309362306a36Sopenharmony_ci * The rpc_xprt_ops for the server backchannel 309462306a36Sopenharmony_ci */ 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_cistatic const struct rpc_xprt_ops bc_tcp_ops = { 309762306a36Sopenharmony_ci .reserve_xprt = xprt_reserve_xprt, 309862306a36Sopenharmony_ci .release_xprt = xprt_release_xprt, 309962306a36Sopenharmony_ci .alloc_slot = xprt_alloc_slot, 310062306a36Sopenharmony_ci .free_slot = xprt_free_slot, 310162306a36Sopenharmony_ci .buf_alloc = bc_malloc, 310262306a36Sopenharmony_ci .buf_free = bc_free, 310362306a36Sopenharmony_ci .send_request = bc_send_request, 310462306a36Sopenharmony_ci .wait_for_reply_request = xprt_wait_for_reply_request_def, 310562306a36Sopenharmony_ci .close = bc_close, 310662306a36Sopenharmony_ci .destroy = bc_destroy, 310762306a36Sopenharmony_ci .print_stats = xs_tcp_print_stats, 310862306a36Sopenharmony_ci .enable_swap = xs_enable_swap, 310962306a36Sopenharmony_ci .disable_swap = xs_disable_swap, 311062306a36Sopenharmony_ci .inject_disconnect = xs_inject_disconnect, 311162306a36Sopenharmony_ci}; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_cistatic int xs_init_anyaddr(const int family, struct sockaddr *sap) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci static const struct sockaddr_in sin = { 311662306a36Sopenharmony_ci .sin_family = AF_INET, 311762306a36Sopenharmony_ci .sin_addr.s_addr = htonl(INADDR_ANY), 311862306a36Sopenharmony_ci }; 311962306a36Sopenharmony_ci static const struct sockaddr_in6 sin6 = { 312062306a36Sopenharmony_ci .sin6_family = AF_INET6, 312162306a36Sopenharmony_ci .sin6_addr = IN6ADDR_ANY_INIT, 312262306a36Sopenharmony_ci }; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci switch (family) { 312562306a36Sopenharmony_ci case AF_LOCAL: 312662306a36Sopenharmony_ci break; 312762306a36Sopenharmony_ci case AF_INET: 312862306a36Sopenharmony_ci memcpy(sap, &sin, sizeof(sin)); 312962306a36Sopenharmony_ci break; 313062306a36Sopenharmony_ci case AF_INET6: 313162306a36Sopenharmony_ci memcpy(sap, &sin6, sizeof(sin6)); 313262306a36Sopenharmony_ci break; 313362306a36Sopenharmony_ci default: 313462306a36Sopenharmony_ci dprintk("RPC: %s: Bad address family\n", __func__); 313562306a36Sopenharmony_ci return -EAFNOSUPPORT; 313662306a36Sopenharmony_ci } 313762306a36Sopenharmony_ci return 0; 313862306a36Sopenharmony_ci} 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, 314162306a36Sopenharmony_ci unsigned int slot_table_size, 314262306a36Sopenharmony_ci unsigned int max_slot_table_size) 314362306a36Sopenharmony_ci{ 314462306a36Sopenharmony_ci struct rpc_xprt *xprt; 314562306a36Sopenharmony_ci struct sock_xprt *new; 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci if (args->addrlen > sizeof(xprt->addr)) { 314862306a36Sopenharmony_ci dprintk("RPC: xs_setup_xprt: address too large\n"); 314962306a36Sopenharmony_ci return ERR_PTR(-EBADF); 315062306a36Sopenharmony_ci } 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size, 315362306a36Sopenharmony_ci max_slot_table_size); 315462306a36Sopenharmony_ci if (xprt == NULL) { 315562306a36Sopenharmony_ci dprintk("RPC: xs_setup_xprt: couldn't allocate " 315662306a36Sopenharmony_ci "rpc_xprt\n"); 315762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 315862306a36Sopenharmony_ci } 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_ci new = container_of(xprt, struct sock_xprt, xprt); 316162306a36Sopenharmony_ci mutex_init(&new->recv_mutex); 316262306a36Sopenharmony_ci memcpy(&xprt->addr, args->dstaddr, args->addrlen); 316362306a36Sopenharmony_ci xprt->addrlen = args->addrlen; 316462306a36Sopenharmony_ci if (args->srcaddr) 316562306a36Sopenharmony_ci memcpy(&new->srcaddr, args->srcaddr, args->addrlen); 316662306a36Sopenharmony_ci else { 316762306a36Sopenharmony_ci int err; 316862306a36Sopenharmony_ci err = xs_init_anyaddr(args->dstaddr->sa_family, 316962306a36Sopenharmony_ci (struct sockaddr *)&new->srcaddr); 317062306a36Sopenharmony_ci if (err != 0) { 317162306a36Sopenharmony_ci xprt_free(xprt); 317262306a36Sopenharmony_ci return ERR_PTR(err); 317362306a36Sopenharmony_ci } 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci return xprt; 317762306a36Sopenharmony_ci} 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_cistatic const struct rpc_timeout xs_local_default_timeout = { 318062306a36Sopenharmony_ci .to_initval = 10 * HZ, 318162306a36Sopenharmony_ci .to_maxval = 10 * HZ, 318262306a36Sopenharmony_ci .to_retries = 2, 318362306a36Sopenharmony_ci}; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci/** 318662306a36Sopenharmony_ci * xs_setup_local - Set up transport to use an AF_LOCAL socket 318762306a36Sopenharmony_ci * @args: rpc transport creation arguments 318862306a36Sopenharmony_ci * 318962306a36Sopenharmony_ci * AF_LOCAL is a "tpi_cots_ord" transport, just like TCP 319062306a36Sopenharmony_ci */ 319162306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_local(struct xprt_create *args) 319262306a36Sopenharmony_ci{ 319362306a36Sopenharmony_ci struct sockaddr_un *sun = (struct sockaddr_un *)args->dstaddr; 319462306a36Sopenharmony_ci struct sock_xprt *transport; 319562306a36Sopenharmony_ci struct rpc_xprt *xprt; 319662306a36Sopenharmony_ci struct rpc_xprt *ret; 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, 319962306a36Sopenharmony_ci xprt_max_tcp_slot_table_entries); 320062306a36Sopenharmony_ci if (IS_ERR(xprt)) 320162306a36Sopenharmony_ci return xprt; 320262306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci xprt->prot = 0; 320562306a36Sopenharmony_ci xprt->xprt_class = &xs_local_transport; 320662306a36Sopenharmony_ci xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci xprt->bind_timeout = XS_BIND_TO; 320962306a36Sopenharmony_ci xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; 321062306a36Sopenharmony_ci xprt->idle_timeout = XS_IDLE_DISC_TO; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci xprt->ops = &xs_local_ops; 321362306a36Sopenharmony_ci xprt->timeout = &xs_local_default_timeout; 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn); 321662306a36Sopenharmony_ci INIT_WORK(&transport->error_worker, xs_error_handle); 321762306a36Sopenharmony_ci INIT_DELAYED_WORK(&transport->connect_worker, xs_dummy_setup_socket); 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci switch (sun->sun_family) { 322062306a36Sopenharmony_ci case AF_LOCAL: 322162306a36Sopenharmony_ci if (sun->sun_path[0] != '/' && sun->sun_path[0] != '\0') { 322262306a36Sopenharmony_ci dprintk("RPC: bad AF_LOCAL address: %s\n", 322362306a36Sopenharmony_ci sun->sun_path); 322462306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 322562306a36Sopenharmony_ci goto out_err; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ci xprt_set_bound(xprt); 322862306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL); 322962306a36Sopenharmony_ci break; 323062306a36Sopenharmony_ci default: 323162306a36Sopenharmony_ci ret = ERR_PTR(-EAFNOSUPPORT); 323262306a36Sopenharmony_ci goto out_err; 323362306a36Sopenharmony_ci } 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s via AF_LOCAL\n", 323662306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR]); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci if (try_module_get(THIS_MODULE)) 323962306a36Sopenharmony_ci return xprt; 324062306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 324162306a36Sopenharmony_ciout_err: 324262306a36Sopenharmony_ci xs_xprt_free(xprt); 324362306a36Sopenharmony_ci return ret; 324462306a36Sopenharmony_ci} 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_cistatic const struct rpc_timeout xs_udp_default_timeout = { 324762306a36Sopenharmony_ci .to_initval = 5 * HZ, 324862306a36Sopenharmony_ci .to_maxval = 30 * HZ, 324962306a36Sopenharmony_ci .to_increment = 5 * HZ, 325062306a36Sopenharmony_ci .to_retries = 5, 325162306a36Sopenharmony_ci}; 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci/** 325462306a36Sopenharmony_ci * xs_setup_udp - Set up transport to use a UDP socket 325562306a36Sopenharmony_ci * @args: rpc transport creation arguments 325662306a36Sopenharmony_ci * 325762306a36Sopenharmony_ci */ 325862306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_udp(struct xprt_create *args) 325962306a36Sopenharmony_ci{ 326062306a36Sopenharmony_ci struct sockaddr *addr = args->dstaddr; 326162306a36Sopenharmony_ci struct rpc_xprt *xprt; 326262306a36Sopenharmony_ci struct sock_xprt *transport; 326362306a36Sopenharmony_ci struct rpc_xprt *ret; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries, 326662306a36Sopenharmony_ci xprt_udp_slot_table_entries); 326762306a36Sopenharmony_ci if (IS_ERR(xprt)) 326862306a36Sopenharmony_ci return xprt; 326962306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci xprt->prot = IPPROTO_UDP; 327262306a36Sopenharmony_ci xprt->xprt_class = &xs_udp_transport; 327362306a36Sopenharmony_ci /* XXX: header size can vary due to auth type, IPv6, etc. */ 327462306a36Sopenharmony_ci xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci xprt->bind_timeout = XS_BIND_TO; 327762306a36Sopenharmony_ci xprt->reestablish_timeout = XS_UDP_REEST_TO; 327862306a36Sopenharmony_ci xprt->idle_timeout = XS_IDLE_DISC_TO; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci xprt->ops = &xs_udp_ops; 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci xprt->timeout = &xs_udp_default_timeout; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci INIT_WORK(&transport->recv_worker, xs_udp_data_receive_workfn); 328562306a36Sopenharmony_ci INIT_WORK(&transport->error_worker, xs_error_handle); 328662306a36Sopenharmony_ci INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_setup_socket); 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci switch (addr->sa_family) { 328962306a36Sopenharmony_ci case AF_INET: 329062306a36Sopenharmony_ci if (((struct sockaddr_in *)addr)->sin_port != htons(0)) 329162306a36Sopenharmony_ci xprt_set_bound(xprt); 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP); 329462306a36Sopenharmony_ci break; 329562306a36Sopenharmony_ci case AF_INET6: 329662306a36Sopenharmony_ci if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) 329762306a36Sopenharmony_ci xprt_set_bound(xprt); 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6); 330062306a36Sopenharmony_ci break; 330162306a36Sopenharmony_ci default: 330262306a36Sopenharmony_ci ret = ERR_PTR(-EAFNOSUPPORT); 330362306a36Sopenharmony_ci goto out_err; 330462306a36Sopenharmony_ci } 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci if (xprt_bound(xprt)) 330762306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (port %s) via %s\n", 330862306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 330962306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT], 331062306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 331162306a36Sopenharmony_ci else 331262306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (autobind) via %s\n", 331362306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 331462306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci if (try_module_get(THIS_MODULE)) 331762306a36Sopenharmony_ci return xprt; 331862306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 331962306a36Sopenharmony_ciout_err: 332062306a36Sopenharmony_ci xs_xprt_free(xprt); 332162306a36Sopenharmony_ci return ret; 332262306a36Sopenharmony_ci} 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_cistatic const struct rpc_timeout xs_tcp_default_timeout = { 332562306a36Sopenharmony_ci .to_initval = 60 * HZ, 332662306a36Sopenharmony_ci .to_maxval = 60 * HZ, 332762306a36Sopenharmony_ci .to_retries = 2, 332862306a36Sopenharmony_ci}; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci/** 333162306a36Sopenharmony_ci * xs_setup_tcp - Set up transport to use a TCP socket 333262306a36Sopenharmony_ci * @args: rpc transport creation arguments 333362306a36Sopenharmony_ci * 333462306a36Sopenharmony_ci */ 333562306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) 333662306a36Sopenharmony_ci{ 333762306a36Sopenharmony_ci struct sockaddr *addr = args->dstaddr; 333862306a36Sopenharmony_ci struct rpc_xprt *xprt; 333962306a36Sopenharmony_ci struct sock_xprt *transport; 334062306a36Sopenharmony_ci struct rpc_xprt *ret; 334162306a36Sopenharmony_ci unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries; 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci if (args->flags & XPRT_CREATE_INFINITE_SLOTS) 334462306a36Sopenharmony_ci max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, 334762306a36Sopenharmony_ci max_slot_table_size); 334862306a36Sopenharmony_ci if (IS_ERR(xprt)) 334962306a36Sopenharmony_ci return xprt; 335062306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci xprt->prot = IPPROTO_TCP; 335362306a36Sopenharmony_ci xprt->xprt_class = &xs_tcp_transport; 335462306a36Sopenharmony_ci xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci xprt->bind_timeout = XS_BIND_TO; 335762306a36Sopenharmony_ci xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; 335862306a36Sopenharmony_ci xprt->idle_timeout = XS_IDLE_DISC_TO; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci xprt->ops = &xs_tcp_ops; 336162306a36Sopenharmony_ci xprt->timeout = &xs_tcp_default_timeout; 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci xprt->max_reconnect_timeout = xprt->timeout->to_maxval; 336462306a36Sopenharmony_ci if (args->reconnect_timeout) 336562306a36Sopenharmony_ci xprt->max_reconnect_timeout = args->reconnect_timeout; 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci xprt->connect_timeout = xprt->timeout->to_initval * 336862306a36Sopenharmony_ci (xprt->timeout->to_retries + 1); 336962306a36Sopenharmony_ci if (args->connect_timeout) 337062306a36Sopenharmony_ci xs_tcp_do_set_connect_timeout(xprt, args->connect_timeout); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn); 337362306a36Sopenharmony_ci INIT_WORK(&transport->error_worker, xs_error_handle); 337462306a36Sopenharmony_ci INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket); 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci switch (addr->sa_family) { 337762306a36Sopenharmony_ci case AF_INET: 337862306a36Sopenharmony_ci if (((struct sockaddr_in *)addr)->sin_port != htons(0)) 337962306a36Sopenharmony_ci xprt_set_bound(xprt); 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP); 338262306a36Sopenharmony_ci break; 338362306a36Sopenharmony_ci case AF_INET6: 338462306a36Sopenharmony_ci if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) 338562306a36Sopenharmony_ci xprt_set_bound(xprt); 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6); 338862306a36Sopenharmony_ci break; 338962306a36Sopenharmony_ci default: 339062306a36Sopenharmony_ci ret = ERR_PTR(-EAFNOSUPPORT); 339162306a36Sopenharmony_ci goto out_err; 339262306a36Sopenharmony_ci } 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci if (xprt_bound(xprt)) 339562306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (port %s) via %s\n", 339662306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 339762306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT], 339862306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 339962306a36Sopenharmony_ci else 340062306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (autobind) via %s\n", 340162306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 340262306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci if (try_module_get(THIS_MODULE)) 340562306a36Sopenharmony_ci return xprt; 340662306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 340762306a36Sopenharmony_ciout_err: 340862306a36Sopenharmony_ci xs_xprt_free(xprt); 340962306a36Sopenharmony_ci return ret; 341062306a36Sopenharmony_ci} 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci/** 341362306a36Sopenharmony_ci * xs_setup_tcp_tls - Set up transport to use a TCP with TLS 341462306a36Sopenharmony_ci * @args: rpc transport creation arguments 341562306a36Sopenharmony_ci * 341662306a36Sopenharmony_ci */ 341762306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_tcp_tls(struct xprt_create *args) 341862306a36Sopenharmony_ci{ 341962306a36Sopenharmony_ci struct sockaddr *addr = args->dstaddr; 342062306a36Sopenharmony_ci struct rpc_xprt *xprt; 342162306a36Sopenharmony_ci struct sock_xprt *transport; 342262306a36Sopenharmony_ci struct rpc_xprt *ret; 342362306a36Sopenharmony_ci unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries; 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci if (args->flags & XPRT_CREATE_INFINITE_SLOTS) 342662306a36Sopenharmony_ci max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT; 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, 342962306a36Sopenharmony_ci max_slot_table_size); 343062306a36Sopenharmony_ci if (IS_ERR(xprt)) 343162306a36Sopenharmony_ci return xprt; 343262306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci xprt->prot = IPPROTO_TCP; 343562306a36Sopenharmony_ci xprt->xprt_class = &xs_tcp_transport; 343662306a36Sopenharmony_ci xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; 343762306a36Sopenharmony_ci 343862306a36Sopenharmony_ci xprt->bind_timeout = XS_BIND_TO; 343962306a36Sopenharmony_ci xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; 344062306a36Sopenharmony_ci xprt->idle_timeout = XS_IDLE_DISC_TO; 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci xprt->ops = &xs_tcp_ops; 344362306a36Sopenharmony_ci xprt->timeout = &xs_tcp_default_timeout; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci xprt->max_reconnect_timeout = xprt->timeout->to_maxval; 344662306a36Sopenharmony_ci xprt->connect_timeout = xprt->timeout->to_initval * 344762306a36Sopenharmony_ci (xprt->timeout->to_retries + 1); 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn); 345062306a36Sopenharmony_ci INIT_WORK(&transport->error_worker, xs_error_handle); 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci switch (args->xprtsec.policy) { 345362306a36Sopenharmony_ci case RPC_XPRTSEC_TLS_ANON: 345462306a36Sopenharmony_ci case RPC_XPRTSEC_TLS_X509: 345562306a36Sopenharmony_ci xprt->xprtsec = args->xprtsec; 345662306a36Sopenharmony_ci INIT_DELAYED_WORK(&transport->connect_worker, 345762306a36Sopenharmony_ci xs_tcp_tls_setup_socket); 345862306a36Sopenharmony_ci break; 345962306a36Sopenharmony_ci default: 346062306a36Sopenharmony_ci ret = ERR_PTR(-EACCES); 346162306a36Sopenharmony_ci goto out_err; 346262306a36Sopenharmony_ci } 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci switch (addr->sa_family) { 346562306a36Sopenharmony_ci case AF_INET: 346662306a36Sopenharmony_ci if (((struct sockaddr_in *)addr)->sin_port != htons(0)) 346762306a36Sopenharmony_ci xprt_set_bound(xprt); 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP); 347062306a36Sopenharmony_ci break; 347162306a36Sopenharmony_ci case AF_INET6: 347262306a36Sopenharmony_ci if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) 347362306a36Sopenharmony_ci xprt_set_bound(xprt); 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6); 347662306a36Sopenharmony_ci break; 347762306a36Sopenharmony_ci default: 347862306a36Sopenharmony_ci ret = ERR_PTR(-EAFNOSUPPORT); 347962306a36Sopenharmony_ci goto out_err; 348062306a36Sopenharmony_ci } 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci if (xprt_bound(xprt)) 348362306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (port %s) via %s\n", 348462306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 348562306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT], 348662306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 348762306a36Sopenharmony_ci else 348862306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (autobind) via %s\n", 348962306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 349062306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci if (try_module_get(THIS_MODULE)) 349362306a36Sopenharmony_ci return xprt; 349462306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 349562306a36Sopenharmony_ciout_err: 349662306a36Sopenharmony_ci xs_xprt_free(xprt); 349762306a36Sopenharmony_ci return ret; 349862306a36Sopenharmony_ci} 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci/** 350162306a36Sopenharmony_ci * xs_setup_bc_tcp - Set up transport to use a TCP backchannel socket 350262306a36Sopenharmony_ci * @args: rpc transport creation arguments 350362306a36Sopenharmony_ci * 350462306a36Sopenharmony_ci */ 350562306a36Sopenharmony_cistatic struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) 350662306a36Sopenharmony_ci{ 350762306a36Sopenharmony_ci struct sockaddr *addr = args->dstaddr; 350862306a36Sopenharmony_ci struct rpc_xprt *xprt; 350962306a36Sopenharmony_ci struct sock_xprt *transport; 351062306a36Sopenharmony_ci struct svc_sock *bc_sock; 351162306a36Sopenharmony_ci struct rpc_xprt *ret; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, 351462306a36Sopenharmony_ci xprt_tcp_slot_table_entries); 351562306a36Sopenharmony_ci if (IS_ERR(xprt)) 351662306a36Sopenharmony_ci return xprt; 351762306a36Sopenharmony_ci transport = container_of(xprt, struct sock_xprt, xprt); 351862306a36Sopenharmony_ci 351962306a36Sopenharmony_ci xprt->prot = IPPROTO_TCP; 352062306a36Sopenharmony_ci xprt->xprt_class = &xs_bc_tcp_transport; 352162306a36Sopenharmony_ci xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; 352262306a36Sopenharmony_ci xprt->timeout = &xs_tcp_default_timeout; 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci /* backchannel */ 352562306a36Sopenharmony_ci xprt_set_bound(xprt); 352662306a36Sopenharmony_ci xprt->bind_timeout = 0; 352762306a36Sopenharmony_ci xprt->reestablish_timeout = 0; 352862306a36Sopenharmony_ci xprt->idle_timeout = 0; 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci xprt->ops = &bc_tcp_ops; 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci switch (addr->sa_family) { 353362306a36Sopenharmony_ci case AF_INET: 353462306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", 353562306a36Sopenharmony_ci RPCBIND_NETID_TCP); 353662306a36Sopenharmony_ci break; 353762306a36Sopenharmony_ci case AF_INET6: 353862306a36Sopenharmony_ci xs_format_peer_addresses(xprt, "tcp", 353962306a36Sopenharmony_ci RPCBIND_NETID_TCP6); 354062306a36Sopenharmony_ci break; 354162306a36Sopenharmony_ci default: 354262306a36Sopenharmony_ci ret = ERR_PTR(-EAFNOSUPPORT); 354362306a36Sopenharmony_ci goto out_err; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci dprintk("RPC: set up xprt to %s (port %s) via %s\n", 354762306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_ADDR], 354862306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PORT], 354962306a36Sopenharmony_ci xprt->address_strings[RPC_DISPLAY_PROTO]); 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci /* 355262306a36Sopenharmony_ci * Once we've associated a backchannel xprt with a connection, 355362306a36Sopenharmony_ci * we want to keep it around as long as the connection lasts, 355462306a36Sopenharmony_ci * in case we need to start using it for a backchannel again; 355562306a36Sopenharmony_ci * this reference won't be dropped until bc_xprt is destroyed. 355662306a36Sopenharmony_ci */ 355762306a36Sopenharmony_ci xprt_get(xprt); 355862306a36Sopenharmony_ci args->bc_xprt->xpt_bc_xprt = xprt; 355962306a36Sopenharmony_ci xprt->bc_xprt = args->bc_xprt; 356062306a36Sopenharmony_ci bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt); 356162306a36Sopenharmony_ci transport->sock = bc_sock->sk_sock; 356262306a36Sopenharmony_ci transport->inet = bc_sock->sk_sk; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci /* 356562306a36Sopenharmony_ci * Since we don't want connections for the backchannel, we set 356662306a36Sopenharmony_ci * the xprt status to connected 356762306a36Sopenharmony_ci */ 356862306a36Sopenharmony_ci xprt_set_connected(xprt); 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci if (try_module_get(THIS_MODULE)) 357162306a36Sopenharmony_ci return xprt; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci args->bc_xprt->xpt_bc_xprt = NULL; 357462306a36Sopenharmony_ci args->bc_xprt->xpt_bc_xps = NULL; 357562306a36Sopenharmony_ci xprt_put(xprt); 357662306a36Sopenharmony_ci ret = ERR_PTR(-EINVAL); 357762306a36Sopenharmony_ciout_err: 357862306a36Sopenharmony_ci xs_xprt_free(xprt); 357962306a36Sopenharmony_ci return ret; 358062306a36Sopenharmony_ci} 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_cistatic struct xprt_class xs_local_transport = { 358362306a36Sopenharmony_ci .list = LIST_HEAD_INIT(xs_local_transport.list), 358462306a36Sopenharmony_ci .name = "named UNIX socket", 358562306a36Sopenharmony_ci .owner = THIS_MODULE, 358662306a36Sopenharmony_ci .ident = XPRT_TRANSPORT_LOCAL, 358762306a36Sopenharmony_ci .setup = xs_setup_local, 358862306a36Sopenharmony_ci .netid = { "" }, 358962306a36Sopenharmony_ci}; 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_cistatic struct xprt_class xs_udp_transport = { 359262306a36Sopenharmony_ci .list = LIST_HEAD_INIT(xs_udp_transport.list), 359362306a36Sopenharmony_ci .name = "udp", 359462306a36Sopenharmony_ci .owner = THIS_MODULE, 359562306a36Sopenharmony_ci .ident = XPRT_TRANSPORT_UDP, 359662306a36Sopenharmony_ci .setup = xs_setup_udp, 359762306a36Sopenharmony_ci .netid = { "udp", "udp6", "" }, 359862306a36Sopenharmony_ci}; 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_cistatic struct xprt_class xs_tcp_transport = { 360162306a36Sopenharmony_ci .list = LIST_HEAD_INIT(xs_tcp_transport.list), 360262306a36Sopenharmony_ci .name = "tcp", 360362306a36Sopenharmony_ci .owner = THIS_MODULE, 360462306a36Sopenharmony_ci .ident = XPRT_TRANSPORT_TCP, 360562306a36Sopenharmony_ci .setup = xs_setup_tcp, 360662306a36Sopenharmony_ci .netid = { "tcp", "tcp6", "" }, 360762306a36Sopenharmony_ci}; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_cistatic struct xprt_class xs_tcp_tls_transport = { 361062306a36Sopenharmony_ci .list = LIST_HEAD_INIT(xs_tcp_tls_transport.list), 361162306a36Sopenharmony_ci .name = "tcp-with-tls", 361262306a36Sopenharmony_ci .owner = THIS_MODULE, 361362306a36Sopenharmony_ci .ident = XPRT_TRANSPORT_TCP_TLS, 361462306a36Sopenharmony_ci .setup = xs_setup_tcp_tls, 361562306a36Sopenharmony_ci .netid = { "tcp", "tcp6", "" }, 361662306a36Sopenharmony_ci}; 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_cistatic struct xprt_class xs_bc_tcp_transport = { 361962306a36Sopenharmony_ci .list = LIST_HEAD_INIT(xs_bc_tcp_transport.list), 362062306a36Sopenharmony_ci .name = "tcp NFSv4.1 backchannel", 362162306a36Sopenharmony_ci .owner = THIS_MODULE, 362262306a36Sopenharmony_ci .ident = XPRT_TRANSPORT_BC_TCP, 362362306a36Sopenharmony_ci .setup = xs_setup_bc_tcp, 362462306a36Sopenharmony_ci .netid = { "" }, 362562306a36Sopenharmony_ci}; 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci/** 362862306a36Sopenharmony_ci * init_socket_xprt - set up xprtsock's sysctls, register with RPC client 362962306a36Sopenharmony_ci * 363062306a36Sopenharmony_ci */ 363162306a36Sopenharmony_ciint init_socket_xprt(void) 363262306a36Sopenharmony_ci{ 363362306a36Sopenharmony_ci if (!sunrpc_table_header) 363462306a36Sopenharmony_ci sunrpc_table_header = register_sysctl("sunrpc", xs_tunables_table); 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci xprt_register_transport(&xs_local_transport); 363762306a36Sopenharmony_ci xprt_register_transport(&xs_udp_transport); 363862306a36Sopenharmony_ci xprt_register_transport(&xs_tcp_transport); 363962306a36Sopenharmony_ci xprt_register_transport(&xs_tcp_tls_transport); 364062306a36Sopenharmony_ci xprt_register_transport(&xs_bc_tcp_transport); 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci return 0; 364362306a36Sopenharmony_ci} 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci/** 364662306a36Sopenharmony_ci * cleanup_socket_xprt - remove xprtsock's sysctls, unregister 364762306a36Sopenharmony_ci * 364862306a36Sopenharmony_ci */ 364962306a36Sopenharmony_civoid cleanup_socket_xprt(void) 365062306a36Sopenharmony_ci{ 365162306a36Sopenharmony_ci if (sunrpc_table_header) { 365262306a36Sopenharmony_ci unregister_sysctl_table(sunrpc_table_header); 365362306a36Sopenharmony_ci sunrpc_table_header = NULL; 365462306a36Sopenharmony_ci } 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci xprt_unregister_transport(&xs_local_transport); 365762306a36Sopenharmony_ci xprt_unregister_transport(&xs_udp_transport); 365862306a36Sopenharmony_ci xprt_unregister_transport(&xs_tcp_transport); 365962306a36Sopenharmony_ci xprt_unregister_transport(&xs_tcp_tls_transport); 366062306a36Sopenharmony_ci xprt_unregister_transport(&xs_bc_tcp_transport); 366162306a36Sopenharmony_ci} 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_cistatic int param_set_portnr(const char *val, const struct kernel_param *kp) 366462306a36Sopenharmony_ci{ 366562306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, 366662306a36Sopenharmony_ci RPC_MIN_RESVPORT, 366762306a36Sopenharmony_ci RPC_MAX_RESVPORT); 366862306a36Sopenharmony_ci} 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_portnr = { 367162306a36Sopenharmony_ci .set = param_set_portnr, 367262306a36Sopenharmony_ci .get = param_get_uint, 367362306a36Sopenharmony_ci}; 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci#define param_check_portnr(name, p) \ 367662306a36Sopenharmony_ci __param_check(name, p, unsigned int); 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_cimodule_param_named(min_resvport, xprt_min_resvport, portnr, 0644); 367962306a36Sopenharmony_cimodule_param_named(max_resvport, xprt_max_resvport, portnr, 0644); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_cistatic int param_set_slot_table_size(const char *val, 368262306a36Sopenharmony_ci const struct kernel_param *kp) 368362306a36Sopenharmony_ci{ 368462306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, 368562306a36Sopenharmony_ci RPC_MIN_SLOT_TABLE, 368662306a36Sopenharmony_ci RPC_MAX_SLOT_TABLE); 368762306a36Sopenharmony_ci} 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_slot_table_size = { 369062306a36Sopenharmony_ci .set = param_set_slot_table_size, 369162306a36Sopenharmony_ci .get = param_get_uint, 369262306a36Sopenharmony_ci}; 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ci#define param_check_slot_table_size(name, p) \ 369562306a36Sopenharmony_ci __param_check(name, p, unsigned int); 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_cistatic int param_set_max_slot_table_size(const char *val, 369862306a36Sopenharmony_ci const struct kernel_param *kp) 369962306a36Sopenharmony_ci{ 370062306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, 370162306a36Sopenharmony_ci RPC_MIN_SLOT_TABLE, 370262306a36Sopenharmony_ci RPC_MAX_SLOT_TABLE_LIMIT); 370362306a36Sopenharmony_ci} 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_max_slot_table_size = { 370662306a36Sopenharmony_ci .set = param_set_max_slot_table_size, 370762306a36Sopenharmony_ci .get = param_get_uint, 370862306a36Sopenharmony_ci}; 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci#define param_check_max_slot_table_size(name, p) \ 371162306a36Sopenharmony_ci __param_check(name, p, unsigned int); 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_cimodule_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, 371462306a36Sopenharmony_ci slot_table_size, 0644); 371562306a36Sopenharmony_cimodule_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries, 371662306a36Sopenharmony_ci max_slot_table_size, 0644); 371762306a36Sopenharmony_cimodule_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, 371862306a36Sopenharmony_ci slot_table_size, 0644); 3719