18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/net/sunrpc/xprtsock.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Client-side transport implementation for sockets.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * TCP callback races fixes (C) 1998 Red Hat
88c2ecf20Sopenharmony_ci * TCP send fixes (C) 1998 Red Hat
98c2ecf20Sopenharmony_ci * TCP NFS related read + write fixes
108c2ecf20Sopenharmony_ci *  (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Rewrite of larges part of the code in order to stabilize TCP stuff.
138c2ecf20Sopenharmony_ci * Fix behaviour when socket buffer is full.
148c2ecf20Sopenharmony_ci *  (C) 1999 Trond Myklebust <trond.myklebust@fys.uio.no>
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * IP socket transport implementation, (C) 2005 Chuck Lever <cel@netapp.com>
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005.
198c2ecf20Sopenharmony_ci *   <gilles.quillard@bull.net>
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/types.h>
238c2ecf20Sopenharmony_ci#include <linux/string.h>
248c2ecf20Sopenharmony_ci#include <linux/slab.h>
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/capability.h>
278c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
288c2ecf20Sopenharmony_ci#include <linux/errno.h>
298c2ecf20Sopenharmony_ci#include <linux/socket.h>
308c2ecf20Sopenharmony_ci#include <linux/in.h>
318c2ecf20Sopenharmony_ci#include <linux/net.h>
328c2ecf20Sopenharmony_ci#include <linux/mm.h>
338c2ecf20Sopenharmony_ci#include <linux/un.h>
348c2ecf20Sopenharmony_ci#include <linux/udp.h>
358c2ecf20Sopenharmony_ci#include <linux/tcp.h>
368c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
378c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h>
388c2ecf20Sopenharmony_ci#include <linux/sunrpc/sched.h>
398c2ecf20Sopenharmony_ci#include <linux/sunrpc/svcsock.h>
408c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprtsock.h>
418c2ecf20Sopenharmony_ci#include <linux/file.h>
428c2ecf20Sopenharmony_ci#ifdef CONFIG_SUNRPC_BACKCHANNEL
438c2ecf20Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
448c2ecf20Sopenharmony_ci#endif
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <net/sock.h>
478c2ecf20Sopenharmony_ci#include <net/checksum.h>
488c2ecf20Sopenharmony_ci#include <net/udp.h>
498c2ecf20Sopenharmony_ci#include <net/tcp.h>
508c2ecf20Sopenharmony_ci#include <linux/bvec.h>
518c2ecf20Sopenharmony_ci#include <linux/highmem.h>
528c2ecf20Sopenharmony_ci#include <linux/uio.h>
538c2ecf20Sopenharmony_ci#include <linux/sched/mm.h>
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h>
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include "socklib.h"
588c2ecf20Sopenharmony_ci#include "sunrpc.h"
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void xs_close(struct rpc_xprt *xprt);
618c2ecf20Sopenharmony_cistatic void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
628c2ecf20Sopenharmony_ci		struct socket *sock);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * xprtsock tunables
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
688c2ecf20Sopenharmony_cistatic unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
698c2ecf20Sopenharmony_cistatic unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
728c2ecf20Sopenharmony_cistatic unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define XS_TCP_LINGER_TO	(15U * HZ)
758c2ecf20Sopenharmony_cistatic unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * We can register our own files under /proc/sys/sunrpc by
798c2ecf20Sopenharmony_ci * calling register_sysctl_table() again.  The files in that
808c2ecf20Sopenharmony_ci * directory become the union of all files registered there.
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * We simply need to make sure that we don't collide with
838c2ecf20Sopenharmony_ci * someone else's file names!
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
878c2ecf20Sopenharmony_cistatic unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
888c2ecf20Sopenharmony_cistatic unsigned int max_tcp_slot_table_limit = RPC_MAX_SLOT_TABLE_LIMIT;
898c2ecf20Sopenharmony_cistatic unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT;
908c2ecf20Sopenharmony_cistatic unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic struct ctl_table_header *sunrpc_table_header;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci * FIXME: changing the UDP slot table size should also resize the UDP
968c2ecf20Sopenharmony_ci *        socket buffers for existing UDP transports
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_cistatic struct ctl_table xs_tunables_table[] = {
998c2ecf20Sopenharmony_ci	{
1008c2ecf20Sopenharmony_ci		.procname	= "udp_slot_table_entries",
1018c2ecf20Sopenharmony_ci		.data		= &xprt_udp_slot_table_entries,
1028c2ecf20Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
1038c2ecf20Sopenharmony_ci		.mode		= 0644,
1048c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
1058c2ecf20Sopenharmony_ci		.extra1		= &min_slot_table_size,
1068c2ecf20Sopenharmony_ci		.extra2		= &max_slot_table_size
1078c2ecf20Sopenharmony_ci	},
1088c2ecf20Sopenharmony_ci	{
1098c2ecf20Sopenharmony_ci		.procname	= "tcp_slot_table_entries",
1108c2ecf20Sopenharmony_ci		.data		= &xprt_tcp_slot_table_entries,
1118c2ecf20Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
1128c2ecf20Sopenharmony_ci		.mode		= 0644,
1138c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
1148c2ecf20Sopenharmony_ci		.extra1		= &min_slot_table_size,
1158c2ecf20Sopenharmony_ci		.extra2		= &max_slot_table_size
1168c2ecf20Sopenharmony_ci	},
1178c2ecf20Sopenharmony_ci	{
1188c2ecf20Sopenharmony_ci		.procname	= "tcp_max_slot_table_entries",
1198c2ecf20Sopenharmony_ci		.data		= &xprt_max_tcp_slot_table_entries,
1208c2ecf20Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
1218c2ecf20Sopenharmony_ci		.mode		= 0644,
1228c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
1238c2ecf20Sopenharmony_ci		.extra1		= &min_slot_table_size,
1248c2ecf20Sopenharmony_ci		.extra2		= &max_tcp_slot_table_limit
1258c2ecf20Sopenharmony_ci	},
1268c2ecf20Sopenharmony_ci	{
1278c2ecf20Sopenharmony_ci		.procname	= "min_resvport",
1288c2ecf20Sopenharmony_ci		.data		= &xprt_min_resvport,
1298c2ecf20Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
1308c2ecf20Sopenharmony_ci		.mode		= 0644,
1318c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
1328c2ecf20Sopenharmony_ci		.extra1		= &xprt_min_resvport_limit,
1338c2ecf20Sopenharmony_ci		.extra2		= &xprt_max_resvport_limit
1348c2ecf20Sopenharmony_ci	},
1358c2ecf20Sopenharmony_ci	{
1368c2ecf20Sopenharmony_ci		.procname	= "max_resvport",
1378c2ecf20Sopenharmony_ci		.data		= &xprt_max_resvport,
1388c2ecf20Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
1398c2ecf20Sopenharmony_ci		.mode		= 0644,
1408c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
1418c2ecf20Sopenharmony_ci		.extra1		= &xprt_min_resvport_limit,
1428c2ecf20Sopenharmony_ci		.extra2		= &xprt_max_resvport_limit
1438c2ecf20Sopenharmony_ci	},
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		.procname	= "tcp_fin_timeout",
1468c2ecf20Sopenharmony_ci		.data		= &xs_tcp_fin_timeout,
1478c2ecf20Sopenharmony_ci		.maxlen		= sizeof(xs_tcp_fin_timeout),
1488c2ecf20Sopenharmony_ci		.mode		= 0644,
1498c2ecf20Sopenharmony_ci		.proc_handler	= proc_dointvec_jiffies,
1508c2ecf20Sopenharmony_ci	},
1518c2ecf20Sopenharmony_ci	{ },
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic struct ctl_table sunrpc_table[] = {
1558c2ecf20Sopenharmony_ci	{
1568c2ecf20Sopenharmony_ci		.procname	= "sunrpc",
1578c2ecf20Sopenharmony_ci		.mode		= 0555,
1588c2ecf20Sopenharmony_ci		.child		= xs_tunables_table
1598c2ecf20Sopenharmony_ci	},
1608c2ecf20Sopenharmony_ci	{ },
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/*
1648c2ecf20Sopenharmony_ci * Wait duration for a reply from the RPC portmapper.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_ci#define XS_BIND_TO		(60U * HZ)
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/*
1698c2ecf20Sopenharmony_ci * Delay if a UDP socket connect error occurs.  This is most likely some
1708c2ecf20Sopenharmony_ci * kind of resource problem on the local host.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_ci#define XS_UDP_REEST_TO		(2U * HZ)
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/*
1758c2ecf20Sopenharmony_ci * The reestablish timeout allows clients to delay for a bit before attempting
1768c2ecf20Sopenharmony_ci * to reconnect to a server that just dropped our connection.
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * We implement an exponential backoff when trying to reestablish a TCP
1798c2ecf20Sopenharmony_ci * transport connection with the server.  Some servers like to drop a TCP
1808c2ecf20Sopenharmony_ci * connection when they are overworked, so we start with a short timeout and
1818c2ecf20Sopenharmony_ci * increase over time if the server is down or not responding.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_ci#define XS_TCP_INIT_REEST_TO	(3U * HZ)
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/*
1868c2ecf20Sopenharmony_ci * TCP idle timeout; client drops the transport socket if it is idle
1878c2ecf20Sopenharmony_ci * for this long.  Note that we also timeout UDP sockets to prevent
1888c2ecf20Sopenharmony_ci * holding port numbers when there is no RPC traffic.
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_ci#define XS_IDLE_DISC_TO		(5U * 60 * HZ)
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
1938c2ecf20Sopenharmony_ci# undef  RPC_DEBUG_DATA
1948c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY	RPCDBG_TRANS
1958c2ecf20Sopenharmony_ci#endif
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci#ifdef RPC_DEBUG_DATA
1988c2ecf20Sopenharmony_cistatic void xs_pktdump(char *msg, u32 *packet, unsigned int count)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u8 *buf = (u8 *) packet;
2018c2ecf20Sopenharmony_ci	int j;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	dprintk("RPC:       %s\n", msg);
2048c2ecf20Sopenharmony_ci	for (j = 0; j < count && j < 128; j += 4) {
2058c2ecf20Sopenharmony_ci		if (!(j & 31)) {
2068c2ecf20Sopenharmony_ci			if (j)
2078c2ecf20Sopenharmony_ci				dprintk("\n");
2088c2ecf20Sopenharmony_ci			dprintk("0x%04x ", j);
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci		dprintk("%02x%02x%02x%02x ",
2118c2ecf20Sopenharmony_ci			buf[j], buf[j+1], buf[j+2], buf[j+3]);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	dprintk("\n");
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci#else
2168c2ecf20Sopenharmony_cistatic inline void xs_pktdump(char *msg, u32 *packet, unsigned int count)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	/* NOP */
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci#endif
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	return (struct rpc_xprt *) sk->sk_user_data;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	return (struct sockaddr *) &xprt->addr;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic inline struct sockaddr_un *xs_addr_un(struct rpc_xprt *xprt)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	return (struct sockaddr_un *) &xprt->addr;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	return (struct sockaddr_in *) &xprt->addr;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	return (struct sockaddr_in6 *) &xprt->addr;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic void xs_format_common_peer_addresses(struct rpc_xprt *xprt)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct sockaddr *sap = xs_addr(xprt);
2508c2ecf20Sopenharmony_ci	struct sockaddr_in6 *sin6;
2518c2ecf20Sopenharmony_ci	struct sockaddr_in *sin;
2528c2ecf20Sopenharmony_ci	struct sockaddr_un *sun;
2538c2ecf20Sopenharmony_ci	char buf[128];
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	switch (sap->sa_family) {
2568c2ecf20Sopenharmony_ci	case AF_LOCAL:
2578c2ecf20Sopenharmony_ci		sun = xs_addr_un(xprt);
2588c2ecf20Sopenharmony_ci		strlcpy(buf, sun->sun_path, sizeof(buf));
2598c2ecf20Sopenharmony_ci		xprt->address_strings[RPC_DISPLAY_ADDR] =
2608c2ecf20Sopenharmony_ci						kstrdup(buf, GFP_KERNEL);
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	case AF_INET:
2638c2ecf20Sopenharmony_ci		(void)rpc_ntop(sap, buf, sizeof(buf));
2648c2ecf20Sopenharmony_ci		xprt->address_strings[RPC_DISPLAY_ADDR] =
2658c2ecf20Sopenharmony_ci						kstrdup(buf, GFP_KERNEL);
2668c2ecf20Sopenharmony_ci		sin = xs_addr_in(xprt);
2678c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr));
2688c2ecf20Sopenharmony_ci		break;
2698c2ecf20Sopenharmony_ci	case AF_INET6:
2708c2ecf20Sopenharmony_ci		(void)rpc_ntop(sap, buf, sizeof(buf));
2718c2ecf20Sopenharmony_ci		xprt->address_strings[RPC_DISPLAY_ADDR] =
2728c2ecf20Sopenharmony_ci						kstrdup(buf, GFP_KERNEL);
2738c2ecf20Sopenharmony_ci		sin6 = xs_addr_in6(xprt);
2748c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr);
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	default:
2778c2ecf20Sopenharmony_ci		BUG();
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void xs_format_common_peer_ports(struct rpc_xprt *xprt)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct sockaddr *sap = xs_addr(xprt);
2868c2ecf20Sopenharmony_ci	char buf[128];
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap));
2898c2ecf20Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap));
2928c2ecf20Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void xs_format_peer_addresses(struct rpc_xprt *xprt,
2968c2ecf20Sopenharmony_ci				     const char *protocol,
2978c2ecf20Sopenharmony_ci				     const char *netid)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_PROTO] = protocol;
3008c2ecf20Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_NETID] = netid;
3018c2ecf20Sopenharmony_ci	xs_format_common_peer_addresses(xprt);
3028c2ecf20Sopenharmony_ci	xs_format_common_peer_ports(xprt);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void xs_update_peer_port(struct rpc_xprt *xprt)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
3088c2ecf20Sopenharmony_ci	kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	xs_format_common_peer_ports(xprt);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void xs_free_peer_addresses(struct rpc_xprt *xprt)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	unsigned int i;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	for (i = 0; i < RPC_DISPLAY_MAX; i++)
3188c2ecf20Sopenharmony_ci		switch (i) {
3198c2ecf20Sopenharmony_ci		case RPC_DISPLAY_PROTO:
3208c2ecf20Sopenharmony_ci		case RPC_DISPLAY_NETID:
3218c2ecf20Sopenharmony_ci			continue;
3228c2ecf20Sopenharmony_ci		default:
3238c2ecf20Sopenharmony_ci			kfree(xprt->address_strings[i]);
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic size_t
3288c2ecf20Sopenharmony_cixs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	size_t i,n;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	if (!want || !(buf->flags & XDRBUF_SPARSE_PAGES))
3338c2ecf20Sopenharmony_ci		return want;
3348c2ecf20Sopenharmony_ci	n = (buf->page_base + want + PAGE_SIZE - 1) >> PAGE_SHIFT;
3358c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
3368c2ecf20Sopenharmony_ci		if (buf->pages[i])
3378c2ecf20Sopenharmony_ci			continue;
3388c2ecf20Sopenharmony_ci		buf->bvec[i].bv_page = buf->pages[i] = alloc_page(gfp);
3398c2ecf20Sopenharmony_ci		if (!buf->pages[i]) {
3408c2ecf20Sopenharmony_ci			i *= PAGE_SIZE;
3418c2ecf20Sopenharmony_ci			return i > buf->page_base ? i - buf->page_base : 0;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	return want;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic ssize_t
3488c2ecf20Sopenharmony_cixs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	ssize_t ret;
3518c2ecf20Sopenharmony_ci	if (seek != 0)
3528c2ecf20Sopenharmony_ci		iov_iter_advance(&msg->msg_iter, seek);
3538c2ecf20Sopenharmony_ci	ret = sock_recvmsg(sock, msg, flags);
3548c2ecf20Sopenharmony_ci	return ret > 0 ? ret + seek : ret;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic ssize_t
3588c2ecf20Sopenharmony_cixs_read_kvec(struct socket *sock, struct msghdr *msg, int flags,
3598c2ecf20Sopenharmony_ci		struct kvec *kvec, size_t count, size_t seek)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	iov_iter_kvec(&msg->msg_iter, READ, kvec, 1, count);
3628c2ecf20Sopenharmony_ci	return xs_sock_recvmsg(sock, msg, flags, seek);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic ssize_t
3668c2ecf20Sopenharmony_cixs_read_bvec(struct socket *sock, struct msghdr *msg, int flags,
3678c2ecf20Sopenharmony_ci		struct bio_vec *bvec, unsigned long nr, size_t count,
3688c2ecf20Sopenharmony_ci		size_t seek)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	iov_iter_bvec(&msg->msg_iter, READ, bvec, nr, count);
3718c2ecf20Sopenharmony_ci	return xs_sock_recvmsg(sock, msg, flags, seek);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic ssize_t
3758c2ecf20Sopenharmony_cixs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
3768c2ecf20Sopenharmony_ci		size_t count)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	iov_iter_discard(&msg->msg_iter, READ, count);
3798c2ecf20Sopenharmony_ci	return sock_recvmsg(sock, msg, flags);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
3838c2ecf20Sopenharmony_cistatic void
3848c2ecf20Sopenharmony_cixs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct bvec_iter bi = {
3878c2ecf20Sopenharmony_ci		.bi_size = count,
3888c2ecf20Sopenharmony_ci	};
3898c2ecf20Sopenharmony_ci	struct bio_vec bv;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	bvec_iter_advance(bvec, &bi, seek & PAGE_MASK);
3928c2ecf20Sopenharmony_ci	for_each_bvec(bv, bvec, bi, bi)
3938c2ecf20Sopenharmony_ci		flush_dcache_page(bv.bv_page);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci#else
3968c2ecf20Sopenharmony_cistatic inline void
3978c2ecf20Sopenharmony_cixs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci#endif
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic ssize_t
4038c2ecf20Sopenharmony_cixs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
4048c2ecf20Sopenharmony_ci		struct xdr_buf *buf, size_t count, size_t seek, size_t *read)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	size_t want, seek_init = seek, offset = 0;
4078c2ecf20Sopenharmony_ci	ssize_t ret;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	want = min_t(size_t, count, buf->head[0].iov_len);
4108c2ecf20Sopenharmony_ci	if (seek < want) {
4118c2ecf20Sopenharmony_ci		ret = xs_read_kvec(sock, msg, flags, &buf->head[0], want, seek);
4128c2ecf20Sopenharmony_ci		if (ret <= 0)
4138c2ecf20Sopenharmony_ci			goto sock_err;
4148c2ecf20Sopenharmony_ci		offset += ret;
4158c2ecf20Sopenharmony_ci		if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC))
4168c2ecf20Sopenharmony_ci			goto out;
4178c2ecf20Sopenharmony_ci		if (ret != want)
4188c2ecf20Sopenharmony_ci			goto out;
4198c2ecf20Sopenharmony_ci		seek = 0;
4208c2ecf20Sopenharmony_ci	} else {
4218c2ecf20Sopenharmony_ci		seek -= want;
4228c2ecf20Sopenharmony_ci		offset += want;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	want = xs_alloc_sparse_pages(buf,
4268c2ecf20Sopenharmony_ci			min_t(size_t, count - offset, buf->page_len),
4278c2ecf20Sopenharmony_ci			GFP_KERNEL);
4288c2ecf20Sopenharmony_ci	if (seek < want) {
4298c2ecf20Sopenharmony_ci		ret = xs_read_bvec(sock, msg, flags, buf->bvec,
4308c2ecf20Sopenharmony_ci				xdr_buf_pagecount(buf),
4318c2ecf20Sopenharmony_ci				want + buf->page_base,
4328c2ecf20Sopenharmony_ci				seek + buf->page_base);
4338c2ecf20Sopenharmony_ci		if (ret <= 0)
4348c2ecf20Sopenharmony_ci			goto sock_err;
4358c2ecf20Sopenharmony_ci		xs_flush_bvec(buf->bvec, ret, seek + buf->page_base);
4368c2ecf20Sopenharmony_ci		ret -= buf->page_base;
4378c2ecf20Sopenharmony_ci		offset += ret;
4388c2ecf20Sopenharmony_ci		if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC))
4398c2ecf20Sopenharmony_ci			goto out;
4408c2ecf20Sopenharmony_ci		if (ret != want)
4418c2ecf20Sopenharmony_ci			goto out;
4428c2ecf20Sopenharmony_ci		seek = 0;
4438c2ecf20Sopenharmony_ci	} else {
4448c2ecf20Sopenharmony_ci		seek -= want;
4458c2ecf20Sopenharmony_ci		offset += want;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	want = min_t(size_t, count - offset, buf->tail[0].iov_len);
4498c2ecf20Sopenharmony_ci	if (seek < want) {
4508c2ecf20Sopenharmony_ci		ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek);
4518c2ecf20Sopenharmony_ci		if (ret <= 0)
4528c2ecf20Sopenharmony_ci			goto sock_err;
4538c2ecf20Sopenharmony_ci		offset += ret;
4548c2ecf20Sopenharmony_ci		if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC))
4558c2ecf20Sopenharmony_ci			goto out;
4568c2ecf20Sopenharmony_ci		if (ret != want)
4578c2ecf20Sopenharmony_ci			goto out;
4588c2ecf20Sopenharmony_ci	} else if (offset < seek_init)
4598c2ecf20Sopenharmony_ci		offset = seek_init;
4608c2ecf20Sopenharmony_ci	ret = -EMSGSIZE;
4618c2ecf20Sopenharmony_ciout:
4628c2ecf20Sopenharmony_ci	*read = offset - seek_init;
4638c2ecf20Sopenharmony_ci	return ret;
4648c2ecf20Sopenharmony_cisock_err:
4658c2ecf20Sopenharmony_ci	offset += seek;
4668c2ecf20Sopenharmony_ci	goto out;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic void
4708c2ecf20Sopenharmony_cixs_read_header(struct sock_xprt *transport, struct xdr_buf *buf)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	if (!transport->recv.copied) {
4738c2ecf20Sopenharmony_ci		if (buf->head[0].iov_len >= transport->recv.offset)
4748c2ecf20Sopenharmony_ci			memcpy(buf->head[0].iov_base,
4758c2ecf20Sopenharmony_ci					&transport->recv.xid,
4768c2ecf20Sopenharmony_ci					transport->recv.offset);
4778c2ecf20Sopenharmony_ci		transport->recv.copied = transport->recv.offset;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic bool
4828c2ecf20Sopenharmony_cixs_read_stream_request_done(struct sock_xprt *transport)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	return transport->recv.fraghdr & cpu_to_be32(RPC_LAST_STREAM_FRAGMENT);
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void
4888c2ecf20Sopenharmony_cixs_read_stream_check_eor(struct sock_xprt *transport,
4898c2ecf20Sopenharmony_ci		struct msghdr *msg)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	if (xs_read_stream_request_done(transport))
4928c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_EOR;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic ssize_t
4968c2ecf20Sopenharmony_cixs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg,
4978c2ecf20Sopenharmony_ci		int flags, struct rpc_rqst *req)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct xdr_buf *buf = &req->rq_private_buf;
5008c2ecf20Sopenharmony_ci	size_t want, read;
5018c2ecf20Sopenharmony_ci	ssize_t ret;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	xs_read_header(transport, buf);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	want = transport->recv.len - transport->recv.offset;
5068c2ecf20Sopenharmony_ci	if (want != 0) {
5078c2ecf20Sopenharmony_ci		ret = xs_read_xdr_buf(transport->sock, msg, flags, buf,
5088c2ecf20Sopenharmony_ci				transport->recv.copied + want,
5098c2ecf20Sopenharmony_ci				transport->recv.copied,
5108c2ecf20Sopenharmony_ci				&read);
5118c2ecf20Sopenharmony_ci		transport->recv.offset += read;
5128c2ecf20Sopenharmony_ci		transport->recv.copied += read;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (transport->recv.offset == transport->recv.len)
5168c2ecf20Sopenharmony_ci		xs_read_stream_check_eor(transport, msg);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (want == 0)
5198c2ecf20Sopenharmony_ci		return 0;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	switch (ret) {
5228c2ecf20Sopenharmony_ci	default:
5238c2ecf20Sopenharmony_ci		break;
5248c2ecf20Sopenharmony_ci	case -EFAULT:
5258c2ecf20Sopenharmony_ci	case -EMSGSIZE:
5268c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
5278c2ecf20Sopenharmony_ci		return read;
5288c2ecf20Sopenharmony_ci	case 0:
5298c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci	return ret < 0 ? ret : read;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic size_t
5358c2ecf20Sopenharmony_cixs_read_stream_headersize(bool isfrag)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	if (isfrag)
5388c2ecf20Sopenharmony_ci		return sizeof(__be32);
5398c2ecf20Sopenharmony_ci	return 3 * sizeof(__be32);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic ssize_t
5438c2ecf20Sopenharmony_cixs_read_stream_header(struct sock_xprt *transport, struct msghdr *msg,
5448c2ecf20Sopenharmony_ci		int flags, size_t want, size_t seek)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct kvec kvec = {
5478c2ecf20Sopenharmony_ci		.iov_base = &transport->recv.fraghdr,
5488c2ecf20Sopenharmony_ci		.iov_len = want,
5498c2ecf20Sopenharmony_ci	};
5508c2ecf20Sopenharmony_ci	return xs_read_kvec(transport->sock, msg, flags, &kvec, want, seek);
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
5548c2ecf20Sopenharmony_cistatic ssize_t
5558c2ecf20Sopenharmony_cixs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
5588c2ecf20Sopenharmony_ci	struct rpc_rqst *req;
5598c2ecf20Sopenharmony_ci	ssize_t ret;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/* Look up and lock the request corresponding to the given XID */
5628c2ecf20Sopenharmony_ci	req = xprt_lookup_bc_request(xprt, transport->recv.xid);
5638c2ecf20Sopenharmony_ci	if (!req) {
5648c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Callback slot table overflowed\n");
5658c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci	if (transport->recv.copied && !req->rq_private_buf.len)
5688c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	ret = xs_read_stream_request(transport, msg, flags, req);
5718c2ecf20Sopenharmony_ci	if (msg->msg_flags & (MSG_EOR|MSG_TRUNC))
5728c2ecf20Sopenharmony_ci		xprt_complete_bc_request(req, transport->recv.copied);
5738c2ecf20Sopenharmony_ci	else
5748c2ecf20Sopenharmony_ci		req->rq_private_buf.len = transport->recv.copied;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return ret;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci#else /* CONFIG_SUNRPC_BACKCHANNEL */
5798c2ecf20Sopenharmony_cistatic ssize_t
5808c2ecf20Sopenharmony_cixs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	return -ESHUTDOWN;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic ssize_t
5878c2ecf20Sopenharmony_cixs_read_stream_reply(struct sock_xprt *transport, struct msghdr *msg, int flags)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
5908c2ecf20Sopenharmony_ci	struct rpc_rqst *req;
5918c2ecf20Sopenharmony_ci	ssize_t ret = 0;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* Look up and lock the request corresponding to the given XID */
5948c2ecf20Sopenharmony_ci	spin_lock(&xprt->queue_lock);
5958c2ecf20Sopenharmony_ci	req = xprt_lookup_rqst(xprt, transport->recv.xid);
5968c2ecf20Sopenharmony_ci	if (!req || (transport->recv.copied && !req->rq_private_buf.len)) {
5978c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
5988c2ecf20Sopenharmony_ci		goto out;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci	xprt_pin_rqst(req);
6018c2ecf20Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	ret = xs_read_stream_request(transport, msg, flags, req);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	spin_lock(&xprt->queue_lock);
6068c2ecf20Sopenharmony_ci	if (msg->msg_flags & (MSG_EOR|MSG_TRUNC))
6078c2ecf20Sopenharmony_ci		xprt_complete_rqst(req->rq_task, transport->recv.copied);
6088c2ecf20Sopenharmony_ci	else
6098c2ecf20Sopenharmony_ci		req->rq_private_buf.len = transport->recv.copied;
6108c2ecf20Sopenharmony_ci	xprt_unpin_rqst(req);
6118c2ecf20Sopenharmony_ciout:
6128c2ecf20Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
6138c2ecf20Sopenharmony_ci	return ret;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic ssize_t
6178c2ecf20Sopenharmony_cixs_read_stream(struct sock_xprt *transport, int flags)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct msghdr msg = { 0 };
6208c2ecf20Sopenharmony_ci	size_t want, read = 0;
6218c2ecf20Sopenharmony_ci	ssize_t ret = 0;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (transport->recv.len == 0) {
6248c2ecf20Sopenharmony_ci		want = xs_read_stream_headersize(transport->recv.copied != 0);
6258c2ecf20Sopenharmony_ci		ret = xs_read_stream_header(transport, &msg, flags, want,
6268c2ecf20Sopenharmony_ci				transport->recv.offset);
6278c2ecf20Sopenharmony_ci		if (ret <= 0)
6288c2ecf20Sopenharmony_ci			goto out_err;
6298c2ecf20Sopenharmony_ci		transport->recv.offset = ret;
6308c2ecf20Sopenharmony_ci		if (transport->recv.offset != want)
6318c2ecf20Sopenharmony_ci			return transport->recv.offset;
6328c2ecf20Sopenharmony_ci		transport->recv.len = be32_to_cpu(transport->recv.fraghdr) &
6338c2ecf20Sopenharmony_ci			RPC_FRAGMENT_SIZE_MASK;
6348c2ecf20Sopenharmony_ci		transport->recv.offset -= sizeof(transport->recv.fraghdr);
6358c2ecf20Sopenharmony_ci		read = ret;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	switch (be32_to_cpu(transport->recv.calldir)) {
6398c2ecf20Sopenharmony_ci	default:
6408c2ecf20Sopenharmony_ci		msg.msg_flags |= MSG_TRUNC;
6418c2ecf20Sopenharmony_ci		break;
6428c2ecf20Sopenharmony_ci	case RPC_CALL:
6438c2ecf20Sopenharmony_ci		ret = xs_read_stream_call(transport, &msg, flags);
6448c2ecf20Sopenharmony_ci		break;
6458c2ecf20Sopenharmony_ci	case RPC_REPLY:
6468c2ecf20Sopenharmony_ci		ret = xs_read_stream_reply(transport, &msg, flags);
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci	if (msg.msg_flags & MSG_TRUNC) {
6498c2ecf20Sopenharmony_ci		transport->recv.calldir = cpu_to_be32(-1);
6508c2ecf20Sopenharmony_ci		transport->recv.copied = -1;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci	if (ret < 0)
6538c2ecf20Sopenharmony_ci		goto out_err;
6548c2ecf20Sopenharmony_ci	read += ret;
6558c2ecf20Sopenharmony_ci	if (transport->recv.offset < transport->recv.len) {
6568c2ecf20Sopenharmony_ci		if (!(msg.msg_flags & MSG_TRUNC))
6578c2ecf20Sopenharmony_ci			return read;
6588c2ecf20Sopenharmony_ci		msg.msg_flags = 0;
6598c2ecf20Sopenharmony_ci		ret = xs_read_discard(transport->sock, &msg, flags,
6608c2ecf20Sopenharmony_ci				transport->recv.len - transport->recv.offset);
6618c2ecf20Sopenharmony_ci		if (ret <= 0)
6628c2ecf20Sopenharmony_ci			goto out_err;
6638c2ecf20Sopenharmony_ci		transport->recv.offset += ret;
6648c2ecf20Sopenharmony_ci		read += ret;
6658c2ecf20Sopenharmony_ci		if (transport->recv.offset != transport->recv.len)
6668c2ecf20Sopenharmony_ci			return read;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	if (xs_read_stream_request_done(transport)) {
6698c2ecf20Sopenharmony_ci		trace_xs_stream_read_request(transport);
6708c2ecf20Sopenharmony_ci		transport->recv.copied = 0;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci	transport->recv.offset = 0;
6738c2ecf20Sopenharmony_ci	transport->recv.len = 0;
6748c2ecf20Sopenharmony_ci	return read;
6758c2ecf20Sopenharmony_ciout_err:
6768c2ecf20Sopenharmony_ci	return ret != 0 ? ret : -ESHUTDOWN;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistatic __poll_t xs_poll_socket(struct sock_xprt *transport)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	return transport->sock->ops->poll(transport->file, transport->sock,
6828c2ecf20Sopenharmony_ci			NULL);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic bool xs_poll_socket_readable(struct sock_xprt *transport)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	__poll_t events = xs_poll_socket(transport);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	return (events & (EPOLLIN | EPOLLRDNORM)) && !(events & EPOLLRDHUP);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic void xs_poll_check_readable(struct sock_xprt *transport)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);
6968c2ecf20Sopenharmony_ci	if (!xs_poll_socket_readable(transport))
6978c2ecf20Sopenharmony_ci		return;
6988c2ecf20Sopenharmony_ci	if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state))
6998c2ecf20Sopenharmony_ci		queue_work(xprtiod_workqueue, &transport->recv_worker);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic void xs_stream_data_receive(struct sock_xprt *transport)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	size_t read = 0;
7058c2ecf20Sopenharmony_ci	ssize_t ret = 0;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	mutex_lock(&transport->recv_mutex);
7088c2ecf20Sopenharmony_ci	if (transport->sock == NULL)
7098c2ecf20Sopenharmony_ci		goto out;
7108c2ecf20Sopenharmony_ci	for (;;) {
7118c2ecf20Sopenharmony_ci		ret = xs_read_stream(transport, MSG_DONTWAIT);
7128c2ecf20Sopenharmony_ci		if (ret < 0)
7138c2ecf20Sopenharmony_ci			break;
7148c2ecf20Sopenharmony_ci		read += ret;
7158c2ecf20Sopenharmony_ci		cond_resched();
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci	if (ret == -ESHUTDOWN)
7188c2ecf20Sopenharmony_ci		kernel_sock_shutdown(transport->sock, SHUT_RDWR);
7198c2ecf20Sopenharmony_ci	else
7208c2ecf20Sopenharmony_ci		xs_poll_check_readable(transport);
7218c2ecf20Sopenharmony_ciout:
7228c2ecf20Sopenharmony_ci	mutex_unlock(&transport->recv_mutex);
7238c2ecf20Sopenharmony_ci	trace_xs_stream_read_data(&transport->xprt, ret, read);
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic void xs_stream_data_receive_workfn(struct work_struct *work)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
7298c2ecf20Sopenharmony_ci		container_of(work, struct sock_xprt, recv_worker);
7308c2ecf20Sopenharmony_ci	unsigned int pflags = memalloc_nofs_save();
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	xs_stream_data_receive(transport);
7338c2ecf20Sopenharmony_ci	memalloc_nofs_restore(pflags);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic void
7378c2ecf20Sopenharmony_cixs_stream_reset_connect(struct sock_xprt *transport)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	transport->recv.offset = 0;
7408c2ecf20Sopenharmony_ci	transport->recv.len = 0;
7418c2ecf20Sopenharmony_ci	transport->recv.copied = 0;
7428c2ecf20Sopenharmony_ci	transport->xmit.offset = 0;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic void
7468c2ecf20Sopenharmony_cixs_stream_start_connect(struct sock_xprt *transport)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	transport->xprt.stat.connect_count++;
7498c2ecf20Sopenharmony_ci	transport->xprt.stat.connect_start = jiffies;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci#define XS_SENDMSG_FLAGS	(MSG_DONTWAIT | MSG_NOSIGNAL)
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci/**
7558c2ecf20Sopenharmony_ci * xs_nospace - handle transmit was incomplete
7568c2ecf20Sopenharmony_ci * @req: pointer to RPC request
7578c2ecf20Sopenharmony_ci * @transport: pointer to struct sock_xprt
7588c2ecf20Sopenharmony_ci *
7598c2ecf20Sopenharmony_ci */
7608c2ecf20Sopenharmony_cistatic int xs_nospace(struct rpc_rqst *req, struct sock_xprt *transport)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
7638c2ecf20Sopenharmony_ci	struct sock *sk = transport->inet;
7648c2ecf20Sopenharmony_ci	int ret = -EAGAIN;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	trace_rpc_socket_nospace(req, transport);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	/* Protect against races with write_space */
7698c2ecf20Sopenharmony_ci	spin_lock(&xprt->transport_lock);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	/* Don't race with disconnect */
7728c2ecf20Sopenharmony_ci	if (xprt_connected(xprt)) {
7738c2ecf20Sopenharmony_ci		struct socket_wq *wq;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		rcu_read_lock();
7768c2ecf20Sopenharmony_ci		wq = rcu_dereference(sk->sk_wq);
7778c2ecf20Sopenharmony_ci		set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags);
7788c2ecf20Sopenharmony_ci		rcu_read_unlock();
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		/* wait for more buffer space */
7818c2ecf20Sopenharmony_ci		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
7828c2ecf20Sopenharmony_ci		sk->sk_write_pending++;
7838c2ecf20Sopenharmony_ci		xprt_wait_for_buffer_space(xprt);
7848c2ecf20Sopenharmony_ci	} else
7858c2ecf20Sopenharmony_ci		ret = -ENOTCONN;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
7888c2ecf20Sopenharmony_ci	return ret;
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic int xs_sock_nospace(struct rpc_rqst *req)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
7948c2ecf20Sopenharmony_ci		container_of(req->rq_xprt, struct sock_xprt, xprt);
7958c2ecf20Sopenharmony_ci	struct sock *sk = transport->inet;
7968c2ecf20Sopenharmony_ci	int ret = -EAGAIN;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	lock_sock(sk);
7998c2ecf20Sopenharmony_ci	if (!sock_writeable(sk))
8008c2ecf20Sopenharmony_ci		ret = xs_nospace(req, transport);
8018c2ecf20Sopenharmony_ci	release_sock(sk);
8028c2ecf20Sopenharmony_ci	return ret;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic int xs_stream_nospace(struct rpc_rqst *req)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
8088c2ecf20Sopenharmony_ci		container_of(req->rq_xprt, struct sock_xprt, xprt);
8098c2ecf20Sopenharmony_ci	struct sock *sk = transport->inet;
8108c2ecf20Sopenharmony_ci	int ret = -EAGAIN;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	lock_sock(sk);
8138c2ecf20Sopenharmony_ci	if (!sk_stream_memory_free(sk))
8148c2ecf20Sopenharmony_ci		ret = xs_nospace(req, transport);
8158c2ecf20Sopenharmony_ci	release_sock(sk);
8168c2ecf20Sopenharmony_ci	return ret;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void
8208c2ecf20Sopenharmony_cixs_stream_prepare_request(struct rpc_rqst *req)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	xdr_free_bvec(&req->rq_rcv_buf);
8238c2ecf20Sopenharmony_ci	req->rq_task->tk_status = xdr_alloc_bvec(&req->rq_rcv_buf, GFP_KERNEL);
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci/*
8278c2ecf20Sopenharmony_ci * Determine if the previous message in the stream was aborted before it
8288c2ecf20Sopenharmony_ci * could complete transmission.
8298c2ecf20Sopenharmony_ci */
8308c2ecf20Sopenharmony_cistatic bool
8318c2ecf20Sopenharmony_cixs_send_request_was_aborted(struct sock_xprt *transport, struct rpc_rqst *req)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	return transport->xmit.offset != 0 && req->rq_bytes_sent == 0;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci/*
8378c2ecf20Sopenharmony_ci * Return the stream record marker field for a record of length < 2^31-1
8388c2ecf20Sopenharmony_ci */
8398c2ecf20Sopenharmony_cistatic rpc_fraghdr
8408c2ecf20Sopenharmony_cixs_stream_record_marker(struct xdr_buf *xdr)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	if (!xdr->len)
8438c2ecf20Sopenharmony_ci		return 0;
8448c2ecf20Sopenharmony_ci	return cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | (u32)xdr->len);
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/**
8488c2ecf20Sopenharmony_ci * xs_local_send_request - write an RPC request to an AF_LOCAL socket
8498c2ecf20Sopenharmony_ci * @req: pointer to RPC request
8508c2ecf20Sopenharmony_ci *
8518c2ecf20Sopenharmony_ci * Return values:
8528c2ecf20Sopenharmony_ci *        0:	The request has been sent
8538c2ecf20Sopenharmony_ci *   EAGAIN:	The socket was blocked, please call again later to
8548c2ecf20Sopenharmony_ci *		complete the request
8558c2ecf20Sopenharmony_ci * ENOTCONN:	Caller needs to invoke connect logic then call again
8568c2ecf20Sopenharmony_ci *    other:	Some other error occured, the request was not sent
8578c2ecf20Sopenharmony_ci */
8588c2ecf20Sopenharmony_cistatic int xs_local_send_request(struct rpc_rqst *req)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
8618c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
8628c2ecf20Sopenharmony_ci				container_of(xprt, struct sock_xprt, xprt);
8638c2ecf20Sopenharmony_ci	struct xdr_buf *xdr = &req->rq_snd_buf;
8648c2ecf20Sopenharmony_ci	rpc_fraghdr rm = xs_stream_record_marker(xdr);
8658c2ecf20Sopenharmony_ci	unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
8668c2ecf20Sopenharmony_ci	struct msghdr msg = {
8678c2ecf20Sopenharmony_ci		.msg_flags	= XS_SENDMSG_FLAGS,
8688c2ecf20Sopenharmony_ci	};
8698c2ecf20Sopenharmony_ci	unsigned int sent;
8708c2ecf20Sopenharmony_ci	int status;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	/* Close the stream if the previous transmission was incomplete */
8738c2ecf20Sopenharmony_ci	if (xs_send_request_was_aborted(transport, req)) {
8748c2ecf20Sopenharmony_ci		xprt_force_disconnect(xprt);
8758c2ecf20Sopenharmony_ci		return -ENOTCONN;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	xs_pktdump("packet data:",
8798c2ecf20Sopenharmony_ci			req->rq_svec->iov_base, req->rq_svec->iov_len);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	req->rq_xtime = ktime_get();
8828c2ecf20Sopenharmony_ci	status = xprt_sock_sendmsg(transport->sock, &msg, xdr,
8838c2ecf20Sopenharmony_ci				   transport->xmit.offset, rm, &sent);
8848c2ecf20Sopenharmony_ci	dprintk("RPC:       %s(%u) = %d\n",
8858c2ecf20Sopenharmony_ci			__func__, xdr->len - transport->xmit.offset, status);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (status == -EAGAIN && sock_writeable(transport->inet))
8888c2ecf20Sopenharmony_ci		status = -ENOBUFS;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (likely(sent > 0) || status == 0) {
8918c2ecf20Sopenharmony_ci		transport->xmit.offset += sent;
8928c2ecf20Sopenharmony_ci		req->rq_bytes_sent = transport->xmit.offset;
8938c2ecf20Sopenharmony_ci		if (likely(req->rq_bytes_sent >= msglen)) {
8948c2ecf20Sopenharmony_ci			req->rq_xmit_bytes_sent += transport->xmit.offset;
8958c2ecf20Sopenharmony_ci			transport->xmit.offset = 0;
8968c2ecf20Sopenharmony_ci			return 0;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci		status = -EAGAIN;
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	switch (status) {
9028c2ecf20Sopenharmony_ci	case -ENOBUFS:
9038c2ecf20Sopenharmony_ci		break;
9048c2ecf20Sopenharmony_ci	case -EAGAIN:
9058c2ecf20Sopenharmony_ci		status = xs_stream_nospace(req);
9068c2ecf20Sopenharmony_ci		break;
9078c2ecf20Sopenharmony_ci	default:
9088c2ecf20Sopenharmony_ci		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
9098c2ecf20Sopenharmony_ci			-status);
9108c2ecf20Sopenharmony_ci		fallthrough;
9118c2ecf20Sopenharmony_ci	case -EPIPE:
9128c2ecf20Sopenharmony_ci		xprt_force_disconnect(xprt);
9138c2ecf20Sopenharmony_ci		status = -ENOTCONN;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	return status;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci/**
9208c2ecf20Sopenharmony_ci * xs_udp_send_request - write an RPC request to a UDP socket
9218c2ecf20Sopenharmony_ci * @req: pointer to RPC request
9228c2ecf20Sopenharmony_ci *
9238c2ecf20Sopenharmony_ci * Return values:
9248c2ecf20Sopenharmony_ci *        0:	The request has been sent
9258c2ecf20Sopenharmony_ci *   EAGAIN:	The socket was blocked, please call again later to
9268c2ecf20Sopenharmony_ci *		complete the request
9278c2ecf20Sopenharmony_ci * ENOTCONN:	Caller needs to invoke connect logic then call again
9288c2ecf20Sopenharmony_ci *    other:	Some other error occurred, the request was not sent
9298c2ecf20Sopenharmony_ci */
9308c2ecf20Sopenharmony_cistatic int xs_udp_send_request(struct rpc_rqst *req)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
9338c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
9348c2ecf20Sopenharmony_ci	struct xdr_buf *xdr = &req->rq_snd_buf;
9358c2ecf20Sopenharmony_ci	struct msghdr msg = {
9368c2ecf20Sopenharmony_ci		.msg_name	= xs_addr(xprt),
9378c2ecf20Sopenharmony_ci		.msg_namelen	= xprt->addrlen,
9388c2ecf20Sopenharmony_ci		.msg_flags	= XS_SENDMSG_FLAGS,
9398c2ecf20Sopenharmony_ci	};
9408c2ecf20Sopenharmony_ci	unsigned int sent;
9418c2ecf20Sopenharmony_ci	int status;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	xs_pktdump("packet data:",
9448c2ecf20Sopenharmony_ci				req->rq_svec->iov_base,
9458c2ecf20Sopenharmony_ci				req->rq_svec->iov_len);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	if (!xprt_bound(xprt))
9488c2ecf20Sopenharmony_ci		return -ENOTCONN;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (!xprt_request_get_cong(xprt, req))
9518c2ecf20Sopenharmony_ci		return -EBADSLT;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	req->rq_xtime = ktime_get();
9548c2ecf20Sopenharmony_ci	status = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, 0, &sent);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_udp_send_request(%u) = %d\n",
9578c2ecf20Sopenharmony_ci			xdr->len, status);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	/* firewall is blocking us, don't return -EAGAIN or we end up looping */
9608c2ecf20Sopenharmony_ci	if (status == -EPERM)
9618c2ecf20Sopenharmony_ci		goto process_status;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	if (status == -EAGAIN && sock_writeable(transport->inet))
9648c2ecf20Sopenharmony_ci		status = -ENOBUFS;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (sent > 0 || status == 0) {
9678c2ecf20Sopenharmony_ci		req->rq_xmit_bytes_sent += sent;
9688c2ecf20Sopenharmony_ci		if (sent >= req->rq_slen)
9698c2ecf20Sopenharmony_ci			return 0;
9708c2ecf20Sopenharmony_ci		/* Still some bytes left; set up for a retry later. */
9718c2ecf20Sopenharmony_ci		status = -EAGAIN;
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ciprocess_status:
9758c2ecf20Sopenharmony_ci	switch (status) {
9768c2ecf20Sopenharmony_ci	case -ENOTSOCK:
9778c2ecf20Sopenharmony_ci		status = -ENOTCONN;
9788c2ecf20Sopenharmony_ci		/* Should we call xs_close() here? */
9798c2ecf20Sopenharmony_ci		break;
9808c2ecf20Sopenharmony_ci	case -EAGAIN:
9818c2ecf20Sopenharmony_ci		status = xs_sock_nospace(req);
9828c2ecf20Sopenharmony_ci		break;
9838c2ecf20Sopenharmony_ci	case -ENETUNREACH:
9848c2ecf20Sopenharmony_ci	case -ENOBUFS:
9858c2ecf20Sopenharmony_ci	case -EPIPE:
9868c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
9878c2ecf20Sopenharmony_ci	case -EPERM:
9888c2ecf20Sopenharmony_ci		/* When the server has died, an ICMP port unreachable message
9898c2ecf20Sopenharmony_ci		 * prompts ECONNREFUSED. */
9908c2ecf20Sopenharmony_ci		break;
9918c2ecf20Sopenharmony_ci	default:
9928c2ecf20Sopenharmony_ci		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
9938c2ecf20Sopenharmony_ci			-status);
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	return status;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci/**
10008c2ecf20Sopenharmony_ci * xs_tcp_send_request - write an RPC request to a TCP socket
10018c2ecf20Sopenharmony_ci * @req: pointer to RPC request
10028c2ecf20Sopenharmony_ci *
10038c2ecf20Sopenharmony_ci * Return values:
10048c2ecf20Sopenharmony_ci *        0:	The request has been sent
10058c2ecf20Sopenharmony_ci *   EAGAIN:	The socket was blocked, please call again later to
10068c2ecf20Sopenharmony_ci *		complete the request
10078c2ecf20Sopenharmony_ci * ENOTCONN:	Caller needs to invoke connect logic then call again
10088c2ecf20Sopenharmony_ci *    other:	Some other error occurred, the request was not sent
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * XXX: In the case of soft timeouts, should we eventually give up
10118c2ecf20Sopenharmony_ci *	if sendmsg is not able to make progress?
10128c2ecf20Sopenharmony_ci */
10138c2ecf20Sopenharmony_cistatic int xs_tcp_send_request(struct rpc_rqst *req)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
10168c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
10178c2ecf20Sopenharmony_ci	struct xdr_buf *xdr = &req->rq_snd_buf;
10188c2ecf20Sopenharmony_ci	rpc_fraghdr rm = xs_stream_record_marker(xdr);
10198c2ecf20Sopenharmony_ci	unsigned int msglen = rm ? req->rq_slen + sizeof(rm) : req->rq_slen;
10208c2ecf20Sopenharmony_ci	struct msghdr msg = {
10218c2ecf20Sopenharmony_ci		.msg_flags	= XS_SENDMSG_FLAGS,
10228c2ecf20Sopenharmony_ci	};
10238c2ecf20Sopenharmony_ci	bool vm_wait = false;
10248c2ecf20Sopenharmony_ci	unsigned int sent;
10258c2ecf20Sopenharmony_ci	int status;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/* Close the stream if the previous transmission was incomplete */
10288c2ecf20Sopenharmony_ci	if (xs_send_request_was_aborted(transport, req)) {
10298c2ecf20Sopenharmony_ci		if (transport->sock != NULL)
10308c2ecf20Sopenharmony_ci			kernel_sock_shutdown(transport->sock, SHUT_RDWR);
10318c2ecf20Sopenharmony_ci		return -ENOTCONN;
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	xs_pktdump("packet data:",
10358c2ecf20Sopenharmony_ci				req->rq_svec->iov_base,
10368c2ecf20Sopenharmony_ci				req->rq_svec->iov_len);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state))
10398c2ecf20Sopenharmony_ci		xs_tcp_set_socket_timeouts(xprt, transport->sock);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* Continue transmitting the packet/record. We must be careful
10428c2ecf20Sopenharmony_ci	 * to cope with writespace callbacks arriving _after_ we have
10438c2ecf20Sopenharmony_ci	 * called sendmsg(). */
10448c2ecf20Sopenharmony_ci	req->rq_xtime = ktime_get();
10458c2ecf20Sopenharmony_ci	while (1) {
10468c2ecf20Sopenharmony_ci		status = xprt_sock_sendmsg(transport->sock, &msg, xdr,
10478c2ecf20Sopenharmony_ci					   transport->xmit.offset, rm, &sent);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci		dprintk("RPC:       xs_tcp_send_request(%u) = %d\n",
10508c2ecf20Sopenharmony_ci				xdr->len - transport->xmit.offset, status);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		/* If we've sent the entire packet, immediately
10538c2ecf20Sopenharmony_ci		 * reset the count of bytes sent. */
10548c2ecf20Sopenharmony_ci		transport->xmit.offset += sent;
10558c2ecf20Sopenharmony_ci		req->rq_bytes_sent = transport->xmit.offset;
10568c2ecf20Sopenharmony_ci		if (likely(req->rq_bytes_sent >= msglen)) {
10578c2ecf20Sopenharmony_ci			req->rq_xmit_bytes_sent += transport->xmit.offset;
10588c2ecf20Sopenharmony_ci			transport->xmit.offset = 0;
10598c2ecf20Sopenharmony_ci			return 0;
10608c2ecf20Sopenharmony_ci		}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci		WARN_ON_ONCE(sent == 0 && status == 0);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		if (status == -EAGAIN ) {
10658c2ecf20Sopenharmony_ci			/*
10668c2ecf20Sopenharmony_ci			 * Return EAGAIN if we're sure we're hitting the
10678c2ecf20Sopenharmony_ci			 * socket send buffer limits.
10688c2ecf20Sopenharmony_ci			 */
10698c2ecf20Sopenharmony_ci			if (test_bit(SOCK_NOSPACE, &transport->sock->flags))
10708c2ecf20Sopenharmony_ci				break;
10718c2ecf20Sopenharmony_ci			/*
10728c2ecf20Sopenharmony_ci			 * Did we hit a memory allocation failure?
10738c2ecf20Sopenharmony_ci			 */
10748c2ecf20Sopenharmony_ci			if (sent == 0) {
10758c2ecf20Sopenharmony_ci				status = -ENOBUFS;
10768c2ecf20Sopenharmony_ci				if (vm_wait)
10778c2ecf20Sopenharmony_ci					break;
10788c2ecf20Sopenharmony_ci				/* Retry, knowing now that we're below the
10798c2ecf20Sopenharmony_ci				 * socket send buffer limit
10808c2ecf20Sopenharmony_ci				 */
10818c2ecf20Sopenharmony_ci				vm_wait = true;
10828c2ecf20Sopenharmony_ci			}
10838c2ecf20Sopenharmony_ci			continue;
10848c2ecf20Sopenharmony_ci		}
10858c2ecf20Sopenharmony_ci		if (status < 0)
10868c2ecf20Sopenharmony_ci			break;
10878c2ecf20Sopenharmony_ci		vm_wait = false;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	switch (status) {
10918c2ecf20Sopenharmony_ci	case -ENOTSOCK:
10928c2ecf20Sopenharmony_ci		status = -ENOTCONN;
10938c2ecf20Sopenharmony_ci		/* Should we call xs_close() here? */
10948c2ecf20Sopenharmony_ci		break;
10958c2ecf20Sopenharmony_ci	case -EAGAIN:
10968c2ecf20Sopenharmony_ci		status = xs_stream_nospace(req);
10978c2ecf20Sopenharmony_ci		break;
10988c2ecf20Sopenharmony_ci	case -ECONNRESET:
10998c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
11008c2ecf20Sopenharmony_ci	case -ENOTCONN:
11018c2ecf20Sopenharmony_ci	case -EADDRINUSE:
11028c2ecf20Sopenharmony_ci	case -ENOBUFS:
11038c2ecf20Sopenharmony_ci	case -EPIPE:
11048c2ecf20Sopenharmony_ci		break;
11058c2ecf20Sopenharmony_ci	default:
11068c2ecf20Sopenharmony_ci		dprintk("RPC:       sendmsg returned unrecognized error %d\n",
11078c2ecf20Sopenharmony_ci			-status);
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return status;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	transport->old_data_ready = sk->sk_data_ready;
11168c2ecf20Sopenharmony_ci	transport->old_state_change = sk->sk_state_change;
11178c2ecf20Sopenharmony_ci	transport->old_write_space = sk->sk_write_space;
11188c2ecf20Sopenharmony_ci	transport->old_error_report = sk->sk_error_report;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	sk->sk_data_ready = transport->old_data_ready;
11248c2ecf20Sopenharmony_ci	sk->sk_state_change = transport->old_state_change;
11258c2ecf20Sopenharmony_ci	sk->sk_write_space = transport->old_write_space;
11268c2ecf20Sopenharmony_ci	sk->sk_error_report = transport->old_error_report;
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic void xs_sock_reset_state_flags(struct rpc_xprt *xprt)
11308c2ecf20Sopenharmony_ci{
11318c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);
11348c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state);
11358c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state);
11368c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state);
11378c2ecf20Sopenharmony_ci}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_cistatic void xs_run_error_worker(struct sock_xprt *transport, unsigned int nr)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	set_bit(nr, &transport->sock_state);
11428c2ecf20Sopenharmony_ci	queue_work(xprtiod_workqueue, &transport->error_worker);
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_cistatic void xs_sock_reset_connection_flags(struct rpc_xprt *xprt)
11468c2ecf20Sopenharmony_ci{
11478c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
11488c2ecf20Sopenharmony_ci	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
11498c2ecf20Sopenharmony_ci	clear_bit(XPRT_CLOSING, &xprt->state);
11508c2ecf20Sopenharmony_ci	xs_sock_reset_state_flags(xprt);
11518c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/**
11558c2ecf20Sopenharmony_ci * xs_error_report - callback to handle TCP socket state errors
11568c2ecf20Sopenharmony_ci * @sk: socket
11578c2ecf20Sopenharmony_ci *
11588c2ecf20Sopenharmony_ci * Note: we don't call sock_error() since there may be a rpc_task
11598c2ecf20Sopenharmony_ci * using the socket, and so we don't want to clear sk->sk_err.
11608c2ecf20Sopenharmony_ci */
11618c2ecf20Sopenharmony_cistatic void xs_error_report(struct sock *sk)
11628c2ecf20Sopenharmony_ci{
11638c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
11648c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
11678c2ecf20Sopenharmony_ci	if (!(xprt = xprt_from_sock(sk)))
11688c2ecf20Sopenharmony_ci		goto out;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
11718c2ecf20Sopenharmony_ci	transport->xprt_err = -sk->sk_err;
11728c2ecf20Sopenharmony_ci	if (transport->xprt_err == 0)
11738c2ecf20Sopenharmony_ci		goto out;
11748c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_error_report client %p, error=%d...\n",
11758c2ecf20Sopenharmony_ci			xprt, -transport->xprt_err);
11768c2ecf20Sopenharmony_ci	trace_rpc_socket_error(xprt, sk->sk_socket, transport->xprt_err);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	/* barrier ensures xprt_err is set before XPRT_SOCK_WAKE_ERROR */
11798c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
11808c2ecf20Sopenharmony_ci	xs_run_error_worker(transport, XPRT_SOCK_WAKE_ERROR);
11818c2ecf20Sopenharmony_ci out:
11828c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic void xs_reset_transport(struct sock_xprt *transport)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci	struct socket *sock = transport->sock;
11888c2ecf20Sopenharmony_ci	struct sock *sk = transport->inet;
11898c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
11908c2ecf20Sopenharmony_ci	struct file *filp = transport->file;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	if (sk == NULL)
11938c2ecf20Sopenharmony_ci		return;
11948c2ecf20Sopenharmony_ci	/*
11958c2ecf20Sopenharmony_ci	 * Make sure we're calling this in a context from which it is safe
11968c2ecf20Sopenharmony_ci	 * to call __fput_sync(). In practice that means rpciod and the
11978c2ecf20Sopenharmony_ci	 * system workqueue.
11988c2ecf20Sopenharmony_ci	 */
11998c2ecf20Sopenharmony_ci	if (!(current->flags & PF_WQ_WORKER)) {
12008c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
12018c2ecf20Sopenharmony_ci		set_bit(XPRT_CLOSE_WAIT, &xprt->state);
12028c2ecf20Sopenharmony_ci		return;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (atomic_read(&transport->xprt.swapper))
12068c2ecf20Sopenharmony_ci		sk_clear_memalloc(sk);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	kernel_sock_shutdown(sock, SHUT_RDWR);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	mutex_lock(&transport->recv_mutex);
12118c2ecf20Sopenharmony_ci	write_lock_bh(&sk->sk_callback_lock);
12128c2ecf20Sopenharmony_ci	transport->inet = NULL;
12138c2ecf20Sopenharmony_ci	transport->sock = NULL;
12148c2ecf20Sopenharmony_ci	transport->file = NULL;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	sk->sk_user_data = NULL;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	xs_restore_old_callbacks(transport, sk);
12198c2ecf20Sopenharmony_ci	xprt_clear_connected(xprt);
12208c2ecf20Sopenharmony_ci	write_unlock_bh(&sk->sk_callback_lock);
12218c2ecf20Sopenharmony_ci	xs_sock_reset_connection_flags(xprt);
12228c2ecf20Sopenharmony_ci	/* Reset stream record info */
12238c2ecf20Sopenharmony_ci	xs_stream_reset_connect(transport);
12248c2ecf20Sopenharmony_ci	mutex_unlock(&transport->recv_mutex);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	trace_rpc_socket_close(xprt, sock);
12278c2ecf20Sopenharmony_ci	__fput_sync(filp);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	xprt_disconnect_done(xprt);
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci/**
12338c2ecf20Sopenharmony_ci * xs_close - close a socket
12348c2ecf20Sopenharmony_ci * @xprt: transport
12358c2ecf20Sopenharmony_ci *
12368c2ecf20Sopenharmony_ci * This is used when all requests are complete; ie, no DRC state remains
12378c2ecf20Sopenharmony_ci * on the server we want to save.
12388c2ecf20Sopenharmony_ci *
12398c2ecf20Sopenharmony_ci * The caller _must_ be holding XPRT_LOCKED in order to avoid issues with
12408c2ecf20Sopenharmony_ci * xs_reset_transport() zeroing the socket from underneath a writer.
12418c2ecf20Sopenharmony_ci */
12428c2ecf20Sopenharmony_cistatic void xs_close(struct rpc_xprt *xprt)
12438c2ecf20Sopenharmony_ci{
12448c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_close xprt %p\n", xprt);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	xs_reset_transport(transport);
12498c2ecf20Sopenharmony_ci	xprt->reestablish_timeout = 0;
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_cistatic void xs_inject_disconnect(struct rpc_xprt *xprt)
12538c2ecf20Sopenharmony_ci{
12548c2ecf20Sopenharmony_ci	dprintk("RPC:       injecting transport disconnect on xprt=%p\n",
12558c2ecf20Sopenharmony_ci		xprt);
12568c2ecf20Sopenharmony_ci	xprt_disconnect_done(xprt);
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic void xs_xprt_free(struct rpc_xprt *xprt)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	xs_free_peer_addresses(xprt);
12628c2ecf20Sopenharmony_ci	xprt_free(xprt);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci/**
12668c2ecf20Sopenharmony_ci * xs_destroy - prepare to shutdown a transport
12678c2ecf20Sopenharmony_ci * @xprt: doomed transport
12688c2ecf20Sopenharmony_ci *
12698c2ecf20Sopenharmony_ci */
12708c2ecf20Sopenharmony_cistatic void xs_destroy(struct rpc_xprt *xprt)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt,
12738c2ecf20Sopenharmony_ci			struct sock_xprt, xprt);
12748c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_destroy xprt %p\n", xprt);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&transport->connect_worker);
12778c2ecf20Sopenharmony_ci	xs_close(xprt);
12788c2ecf20Sopenharmony_ci	cancel_work_sync(&transport->recv_worker);
12798c2ecf20Sopenharmony_ci	cancel_work_sync(&transport->error_worker);
12808c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
12818c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci/**
12858c2ecf20Sopenharmony_ci * xs_udp_data_read_skb - receive callback for UDP sockets
12868c2ecf20Sopenharmony_ci * @xprt: transport
12878c2ecf20Sopenharmony_ci * @sk: socket
12888c2ecf20Sopenharmony_ci * @skb: skbuff
12898c2ecf20Sopenharmony_ci *
12908c2ecf20Sopenharmony_ci */
12918c2ecf20Sopenharmony_cistatic void xs_udp_data_read_skb(struct rpc_xprt *xprt,
12928c2ecf20Sopenharmony_ci		struct sock *sk,
12938c2ecf20Sopenharmony_ci		struct sk_buff *skb)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct rpc_task *task;
12968c2ecf20Sopenharmony_ci	struct rpc_rqst *rovr;
12978c2ecf20Sopenharmony_ci	int repsize, copied;
12988c2ecf20Sopenharmony_ci	u32 _xid;
12998c2ecf20Sopenharmony_ci	__be32 *xp;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	repsize = skb->len;
13028c2ecf20Sopenharmony_ci	if (repsize < 4) {
13038c2ecf20Sopenharmony_ci		dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
13048c2ecf20Sopenharmony_ci		return;
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	/* Copy the XID from the skb... */
13088c2ecf20Sopenharmony_ci	xp = skb_header_pointer(skb, 0, sizeof(_xid), &_xid);
13098c2ecf20Sopenharmony_ci	if (xp == NULL)
13108c2ecf20Sopenharmony_ci		return;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	/* Look up and lock the request corresponding to the given XID */
13138c2ecf20Sopenharmony_ci	spin_lock(&xprt->queue_lock);
13148c2ecf20Sopenharmony_ci	rovr = xprt_lookup_rqst(xprt, *xp);
13158c2ecf20Sopenharmony_ci	if (!rovr)
13168c2ecf20Sopenharmony_ci		goto out_unlock;
13178c2ecf20Sopenharmony_ci	xprt_pin_rqst(rovr);
13188c2ecf20Sopenharmony_ci	xprt_update_rtt(rovr->rq_task);
13198c2ecf20Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
13208c2ecf20Sopenharmony_ci	task = rovr->rq_task;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if ((copied = rovr->rq_private_buf.buflen) > repsize)
13238c2ecf20Sopenharmony_ci		copied = repsize;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	/* Suck it into the iovec, verify checksum if not done by hw. */
13268c2ecf20Sopenharmony_ci	if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) {
13278c2ecf20Sopenharmony_ci		spin_lock(&xprt->queue_lock);
13288c2ecf20Sopenharmony_ci		__UDPX_INC_STATS(sk, UDP_MIB_INERRORS);
13298c2ecf20Sopenharmony_ci		goto out_unpin;
13308c2ecf20Sopenharmony_ci	}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	spin_lock(&xprt->transport_lock);
13348c2ecf20Sopenharmony_ci	xprt_adjust_cwnd(xprt, task, copied);
13358c2ecf20Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
13368c2ecf20Sopenharmony_ci	spin_lock(&xprt->queue_lock);
13378c2ecf20Sopenharmony_ci	xprt_complete_rqst(task, copied);
13388c2ecf20Sopenharmony_ci	__UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS);
13398c2ecf20Sopenharmony_ciout_unpin:
13408c2ecf20Sopenharmony_ci	xprt_unpin_rqst(rovr);
13418c2ecf20Sopenharmony_ci out_unlock:
13428c2ecf20Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_cistatic void xs_udp_data_receive(struct sock_xprt *transport)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
13488c2ecf20Sopenharmony_ci	struct sock *sk;
13498c2ecf20Sopenharmony_ci	int err;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	mutex_lock(&transport->recv_mutex);
13528c2ecf20Sopenharmony_ci	sk = transport->inet;
13538c2ecf20Sopenharmony_ci	if (sk == NULL)
13548c2ecf20Sopenharmony_ci		goto out;
13558c2ecf20Sopenharmony_ci	for (;;) {
13568c2ecf20Sopenharmony_ci		skb = skb_recv_udp(sk, 0, 1, &err);
13578c2ecf20Sopenharmony_ci		if (skb == NULL)
13588c2ecf20Sopenharmony_ci			break;
13598c2ecf20Sopenharmony_ci		xs_udp_data_read_skb(&transport->xprt, sk, skb);
13608c2ecf20Sopenharmony_ci		consume_skb(skb);
13618c2ecf20Sopenharmony_ci		cond_resched();
13628c2ecf20Sopenharmony_ci	}
13638c2ecf20Sopenharmony_ci	xs_poll_check_readable(transport);
13648c2ecf20Sopenharmony_ciout:
13658c2ecf20Sopenharmony_ci	mutex_unlock(&transport->recv_mutex);
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_cistatic void xs_udp_data_receive_workfn(struct work_struct *work)
13698c2ecf20Sopenharmony_ci{
13708c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
13718c2ecf20Sopenharmony_ci		container_of(work, struct sock_xprt, recv_worker);
13728c2ecf20Sopenharmony_ci	unsigned int pflags = memalloc_nofs_save();
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	xs_udp_data_receive(transport);
13758c2ecf20Sopenharmony_ci	memalloc_nofs_restore(pflags);
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci/**
13798c2ecf20Sopenharmony_ci * xs_data_ready - "data ready" callback for UDP sockets
13808c2ecf20Sopenharmony_ci * @sk: socket with data to read
13818c2ecf20Sopenharmony_ci *
13828c2ecf20Sopenharmony_ci */
13838c2ecf20Sopenharmony_cistatic void xs_data_ready(struct sock *sk)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
13888c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_data_ready...\n");
13898c2ecf20Sopenharmony_ci	xprt = xprt_from_sock(sk);
13908c2ecf20Sopenharmony_ci	if (xprt != NULL) {
13918c2ecf20Sopenharmony_ci		struct sock_xprt *transport = container_of(xprt,
13928c2ecf20Sopenharmony_ci				struct sock_xprt, xprt);
13938c2ecf20Sopenharmony_ci		transport->old_data_ready(sk);
13948c2ecf20Sopenharmony_ci		/* Any data means we had a useful conversation, so
13958c2ecf20Sopenharmony_ci		 * then we don't need to delay the next reconnect
13968c2ecf20Sopenharmony_ci		 */
13978c2ecf20Sopenharmony_ci		if (xprt->reestablish_timeout)
13988c2ecf20Sopenharmony_ci			xprt->reestablish_timeout = 0;
13998c2ecf20Sopenharmony_ci		if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state))
14008c2ecf20Sopenharmony_ci			queue_work(xprtiod_workqueue, &transport->recv_worker);
14018c2ecf20Sopenharmony_ci	}
14028c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
14038c2ecf20Sopenharmony_ci}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci/*
14068c2ecf20Sopenharmony_ci * Helper function to force a TCP close if the server is sending
14078c2ecf20Sopenharmony_ci * junk and/or it has put us in CLOSE_WAIT
14088c2ecf20Sopenharmony_ci */
14098c2ecf20Sopenharmony_cistatic void xs_tcp_force_close(struct rpc_xprt *xprt)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci	xprt_force_disconnect(xprt);
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
14158c2ecf20Sopenharmony_cistatic size_t xs_tcp_bc_maxpayload(struct rpc_xprt *xprt)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	return PAGE_SIZE;
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci/**
14228c2ecf20Sopenharmony_ci * xs_tcp_state_change - callback to handle TCP socket state changes
14238c2ecf20Sopenharmony_ci * @sk: socket whose state has changed
14248c2ecf20Sopenharmony_ci *
14258c2ecf20Sopenharmony_ci */
14268c2ecf20Sopenharmony_cistatic void xs_tcp_state_change(struct sock *sk)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
14298c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
14328c2ecf20Sopenharmony_ci	if (!(xprt = xprt_from_sock(sk)))
14338c2ecf20Sopenharmony_ci		goto out;
14348c2ecf20Sopenharmony_ci	dprintk("RPC:       xs_tcp_state_change client %p...\n", xprt);
14358c2ecf20Sopenharmony_ci	dprintk("RPC:       state %x conn %d dead %d zapped %d sk_shutdown %d\n",
14368c2ecf20Sopenharmony_ci			sk->sk_state, xprt_connected(xprt),
14378c2ecf20Sopenharmony_ci			sock_flag(sk, SOCK_DEAD),
14388c2ecf20Sopenharmony_ci			sock_flag(sk, SOCK_ZAPPED),
14398c2ecf20Sopenharmony_ci			sk->sk_shutdown);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
14428c2ecf20Sopenharmony_ci	trace_rpc_socket_state_change(xprt, sk->sk_socket);
14438c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
14448c2ecf20Sopenharmony_ci	case TCP_ESTABLISHED:
14458c2ecf20Sopenharmony_ci		if (!xprt_test_and_set_connected(xprt)) {
14468c2ecf20Sopenharmony_ci			xprt->connect_cookie++;
14478c2ecf20Sopenharmony_ci			clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state);
14488c2ecf20Sopenharmony_ci			xprt_clear_connecting(xprt);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci			xprt->stat.connect_count++;
14518c2ecf20Sopenharmony_ci			xprt->stat.connect_time += (long)jiffies -
14528c2ecf20Sopenharmony_ci						   xprt->stat.connect_start;
14538c2ecf20Sopenharmony_ci			xs_run_error_worker(transport, XPRT_SOCK_WAKE_PENDING);
14548c2ecf20Sopenharmony_ci		}
14558c2ecf20Sopenharmony_ci		break;
14568c2ecf20Sopenharmony_ci	case TCP_FIN_WAIT1:
14578c2ecf20Sopenharmony_ci		/* The client initiated a shutdown of the socket */
14588c2ecf20Sopenharmony_ci		xprt->connect_cookie++;
14598c2ecf20Sopenharmony_ci		xprt->reestablish_timeout = 0;
14608c2ecf20Sopenharmony_ci		set_bit(XPRT_CLOSING, &xprt->state);
14618c2ecf20Sopenharmony_ci		smp_mb__before_atomic();
14628c2ecf20Sopenharmony_ci		clear_bit(XPRT_CONNECTED, &xprt->state);
14638c2ecf20Sopenharmony_ci		clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
14648c2ecf20Sopenharmony_ci		smp_mb__after_atomic();
14658c2ecf20Sopenharmony_ci		break;
14668c2ecf20Sopenharmony_ci	case TCP_CLOSE_WAIT:
14678c2ecf20Sopenharmony_ci		/* The server initiated a shutdown of the socket */
14688c2ecf20Sopenharmony_ci		xprt->connect_cookie++;
14698c2ecf20Sopenharmony_ci		clear_bit(XPRT_CONNECTED, &xprt->state);
14708c2ecf20Sopenharmony_ci		xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
14718c2ecf20Sopenharmony_ci		fallthrough;
14728c2ecf20Sopenharmony_ci	case TCP_CLOSING:
14738c2ecf20Sopenharmony_ci		/*
14748c2ecf20Sopenharmony_ci		 * If the server closed down the connection, make sure that
14758c2ecf20Sopenharmony_ci		 * we back off before reconnecting
14768c2ecf20Sopenharmony_ci		 */
14778c2ecf20Sopenharmony_ci		if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
14788c2ecf20Sopenharmony_ci			xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
14798c2ecf20Sopenharmony_ci		break;
14808c2ecf20Sopenharmony_ci	case TCP_LAST_ACK:
14818c2ecf20Sopenharmony_ci		set_bit(XPRT_CLOSING, &xprt->state);
14828c2ecf20Sopenharmony_ci		smp_mb__before_atomic();
14838c2ecf20Sopenharmony_ci		clear_bit(XPRT_CONNECTED, &xprt->state);
14848c2ecf20Sopenharmony_ci		smp_mb__after_atomic();
14858c2ecf20Sopenharmony_ci		break;
14868c2ecf20Sopenharmony_ci	case TCP_CLOSE:
14878c2ecf20Sopenharmony_ci		if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
14888c2ecf20Sopenharmony_ci					&transport->sock_state))
14898c2ecf20Sopenharmony_ci			xprt_clear_connecting(xprt);
14908c2ecf20Sopenharmony_ci		clear_bit(XPRT_CLOSING, &xprt->state);
14918c2ecf20Sopenharmony_ci		/* Trigger the socket release */
14928c2ecf20Sopenharmony_ci		xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci out:
14958c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
14968c2ecf20Sopenharmony_ci}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic void xs_write_space(struct sock *sk)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	struct socket_wq *wq;
15018c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
15028c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (!sk->sk_socket)
15058c2ecf20Sopenharmony_ci		return;
15068c2ecf20Sopenharmony_ci	clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	if (unlikely(!(xprt = xprt_from_sock(sk))))
15098c2ecf20Sopenharmony_ci		return;
15108c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
15118c2ecf20Sopenharmony_ci	rcu_read_lock();
15128c2ecf20Sopenharmony_ci	wq = rcu_dereference(sk->sk_wq);
15138c2ecf20Sopenharmony_ci	if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
15148c2ecf20Sopenharmony_ci		goto out;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE);
15178c2ecf20Sopenharmony_ci	sk->sk_write_pending--;
15188c2ecf20Sopenharmony_ciout:
15198c2ecf20Sopenharmony_ci	rcu_read_unlock();
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci/**
15238c2ecf20Sopenharmony_ci * xs_udp_write_space - callback invoked when socket buffer space
15248c2ecf20Sopenharmony_ci *                             becomes available
15258c2ecf20Sopenharmony_ci * @sk: socket whose state has changed
15268c2ecf20Sopenharmony_ci *
15278c2ecf20Sopenharmony_ci * Called when more output buffer space is available for this socket.
15288c2ecf20Sopenharmony_ci * We try not to wake our writers until they can make "significant"
15298c2ecf20Sopenharmony_ci * progress, otherwise we'll waste resources thrashing kernel_sendmsg
15308c2ecf20Sopenharmony_ci * with a bunch of small requests.
15318c2ecf20Sopenharmony_ci */
15328c2ecf20Sopenharmony_cistatic void xs_udp_write_space(struct sock *sk)
15338c2ecf20Sopenharmony_ci{
15348c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	/* from net/core/sock.c:sock_def_write_space */
15378c2ecf20Sopenharmony_ci	if (sock_writeable(sk))
15388c2ecf20Sopenharmony_ci		xs_write_space(sk);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci/**
15448c2ecf20Sopenharmony_ci * xs_tcp_write_space - callback invoked when socket buffer space
15458c2ecf20Sopenharmony_ci *                             becomes available
15468c2ecf20Sopenharmony_ci * @sk: socket whose state has changed
15478c2ecf20Sopenharmony_ci *
15488c2ecf20Sopenharmony_ci * Called when more output buffer space is available for this socket.
15498c2ecf20Sopenharmony_ci * We try not to wake our writers until they can make "significant"
15508c2ecf20Sopenharmony_ci * progress, otherwise we'll waste resources thrashing kernel_sendmsg
15518c2ecf20Sopenharmony_ci * with a bunch of small requests.
15528c2ecf20Sopenharmony_ci */
15538c2ecf20Sopenharmony_cistatic void xs_tcp_write_space(struct sock *sk)
15548c2ecf20Sopenharmony_ci{
15558c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	/* from net/core/stream.c:sk_stream_write_space */
15588c2ecf20Sopenharmony_ci	if (sk_stream_is_writeable(sk))
15598c2ecf20Sopenharmony_ci		xs_write_space(sk);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_cistatic void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)
15658c2ecf20Sopenharmony_ci{
15668c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
15678c2ecf20Sopenharmony_ci	struct sock *sk = transport->inet;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	if (transport->rcvsize) {
15708c2ecf20Sopenharmony_ci		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
15718c2ecf20Sopenharmony_ci		sk->sk_rcvbuf = transport->rcvsize * xprt->max_reqs * 2;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci	if (transport->sndsize) {
15748c2ecf20Sopenharmony_ci		sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
15758c2ecf20Sopenharmony_ci		sk->sk_sndbuf = transport->sndsize * xprt->max_reqs * 2;
15768c2ecf20Sopenharmony_ci		sk->sk_write_space(sk);
15778c2ecf20Sopenharmony_ci	}
15788c2ecf20Sopenharmony_ci}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci/**
15818c2ecf20Sopenharmony_ci * xs_udp_set_buffer_size - set send and receive limits
15828c2ecf20Sopenharmony_ci * @xprt: generic transport
15838c2ecf20Sopenharmony_ci * @sndsize: requested size of send buffer, in bytes
15848c2ecf20Sopenharmony_ci * @rcvsize: requested size of receive buffer, in bytes
15858c2ecf20Sopenharmony_ci *
15868c2ecf20Sopenharmony_ci * Set socket send and receive buffer size limits.
15878c2ecf20Sopenharmony_ci */
15888c2ecf20Sopenharmony_cistatic void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize)
15898c2ecf20Sopenharmony_ci{
15908c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	transport->sndsize = 0;
15938c2ecf20Sopenharmony_ci	if (sndsize)
15948c2ecf20Sopenharmony_ci		transport->sndsize = sndsize + 1024;
15958c2ecf20Sopenharmony_ci	transport->rcvsize = 0;
15968c2ecf20Sopenharmony_ci	if (rcvsize)
15978c2ecf20Sopenharmony_ci		transport->rcvsize = rcvsize + 1024;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	xs_udp_do_set_buffer_size(xprt);
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci/**
16038c2ecf20Sopenharmony_ci * xs_udp_timer - called when a retransmit timeout occurs on a UDP transport
16048c2ecf20Sopenharmony_ci * @xprt: controlling transport
16058c2ecf20Sopenharmony_ci * @task: task that timed out
16068c2ecf20Sopenharmony_ci *
16078c2ecf20Sopenharmony_ci * Adjust the congestion window after a retransmit timeout has occurred.
16088c2ecf20Sopenharmony_ci */
16098c2ecf20Sopenharmony_cistatic void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	spin_lock(&xprt->transport_lock);
16128c2ecf20Sopenharmony_ci	xprt_adjust_cwnd(xprt, task, -ETIMEDOUT);
16138c2ecf20Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
16148c2ecf20Sopenharmony_ci}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_cistatic int xs_get_random_port(void)
16178c2ecf20Sopenharmony_ci{
16188c2ecf20Sopenharmony_ci	unsigned short min = xprt_min_resvport, max = xprt_max_resvport;
16198c2ecf20Sopenharmony_ci	unsigned short range;
16208c2ecf20Sopenharmony_ci	unsigned short rand;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	if (max < min)
16238c2ecf20Sopenharmony_ci		return -EADDRINUSE;
16248c2ecf20Sopenharmony_ci	range = max - min + 1;
16258c2ecf20Sopenharmony_ci	rand = (unsigned short) prandom_u32() % range;
16268c2ecf20Sopenharmony_ci	return rand + min;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic unsigned short xs_sock_getport(struct socket *sock)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	struct sockaddr_storage buf;
16328c2ecf20Sopenharmony_ci	unsigned short port = 0;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	if (kernel_getsockname(sock, (struct sockaddr *)&buf) < 0)
16358c2ecf20Sopenharmony_ci		goto out;
16368c2ecf20Sopenharmony_ci	switch (buf.ss_family) {
16378c2ecf20Sopenharmony_ci	case AF_INET6:
16388c2ecf20Sopenharmony_ci		port = ntohs(((struct sockaddr_in6 *)&buf)->sin6_port);
16398c2ecf20Sopenharmony_ci		break;
16408c2ecf20Sopenharmony_ci	case AF_INET:
16418c2ecf20Sopenharmony_ci		port = ntohs(((struct sockaddr_in *)&buf)->sin_port);
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ciout:
16448c2ecf20Sopenharmony_ci	return port;
16458c2ecf20Sopenharmony_ci}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci/**
16488c2ecf20Sopenharmony_ci * xs_set_port - reset the port number in the remote endpoint address
16498c2ecf20Sopenharmony_ci * @xprt: generic transport
16508c2ecf20Sopenharmony_ci * @port: new port number
16518c2ecf20Sopenharmony_ci *
16528c2ecf20Sopenharmony_ci */
16538c2ecf20Sopenharmony_cistatic void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	dprintk("RPC:       setting port for xprt %p to %u\n", xprt, port);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	rpc_set_port(xs_addr(xprt), port);
16588c2ecf20Sopenharmony_ci	xs_update_peer_port(xprt);
16598c2ecf20Sopenharmony_ci}
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_cistatic void xs_set_srcport(struct sock_xprt *transport, struct socket *sock)
16628c2ecf20Sopenharmony_ci{
16638c2ecf20Sopenharmony_ci	if (transport->srcport == 0 && transport->xprt.reuseport)
16648c2ecf20Sopenharmony_ci		transport->srcport = xs_sock_getport(sock);
16658c2ecf20Sopenharmony_ci}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_cistatic int xs_get_srcport(struct sock_xprt *transport)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	int port = transport->srcport;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	if (port == 0 && transport->xprt.resvport)
16728c2ecf20Sopenharmony_ci		port = xs_get_random_port();
16738c2ecf20Sopenharmony_ci	return port;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ciunsigned short get_srcport(struct rpc_xprt *xprt)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
16798c2ecf20Sopenharmony_ci	return xs_sock_getport(sock->sock);
16808c2ecf20Sopenharmony_ci}
16818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_srcport);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
16848c2ecf20Sopenharmony_ci{
16858c2ecf20Sopenharmony_ci	if (transport->srcport != 0)
16868c2ecf20Sopenharmony_ci		transport->srcport = 0;
16878c2ecf20Sopenharmony_ci	if (!transport->xprt.resvport)
16888c2ecf20Sopenharmony_ci		return 0;
16898c2ecf20Sopenharmony_ci	if (port <= xprt_min_resvport || port > xprt_max_resvport)
16908c2ecf20Sopenharmony_ci		return xprt_max_resvport;
16918c2ecf20Sopenharmony_ci	return --port;
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_cistatic int xs_bind(struct sock_xprt *transport, struct socket *sock)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	struct sockaddr_storage myaddr;
16968c2ecf20Sopenharmony_ci	int err, nloop = 0;
16978c2ecf20Sopenharmony_ci	int port = xs_get_srcport(transport);
16988c2ecf20Sopenharmony_ci	unsigned short last;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	/*
17018c2ecf20Sopenharmony_ci	 * If we are asking for any ephemeral port (i.e. port == 0 &&
17028c2ecf20Sopenharmony_ci	 * transport->xprt.resvport == 0), don't bind.  Let the local
17038c2ecf20Sopenharmony_ci	 * port selection happen implicitly when the socket is used
17048c2ecf20Sopenharmony_ci	 * (for example at connect time).
17058c2ecf20Sopenharmony_ci	 *
17068c2ecf20Sopenharmony_ci	 * This ensures that we can continue to establish TCP
17078c2ecf20Sopenharmony_ci	 * connections even when all local ephemeral ports are already
17088c2ecf20Sopenharmony_ci	 * a part of some TCP connection.  This makes no difference
17098c2ecf20Sopenharmony_ci	 * for UDP sockets, but also doens't harm them.
17108c2ecf20Sopenharmony_ci	 *
17118c2ecf20Sopenharmony_ci	 * If we're asking for any reserved port (i.e. port == 0 &&
17128c2ecf20Sopenharmony_ci	 * transport->xprt.resvport == 1) xs_get_srcport above will
17138c2ecf20Sopenharmony_ci	 * ensure that port is non-zero and we will bind as needed.
17148c2ecf20Sopenharmony_ci	 */
17158c2ecf20Sopenharmony_ci	if (port <= 0)
17168c2ecf20Sopenharmony_ci		return port;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
17198c2ecf20Sopenharmony_ci	do {
17208c2ecf20Sopenharmony_ci		rpc_set_port((struct sockaddr *)&myaddr, port);
17218c2ecf20Sopenharmony_ci		err = kernel_bind(sock, (struct sockaddr *)&myaddr,
17228c2ecf20Sopenharmony_ci				transport->xprt.addrlen);
17238c2ecf20Sopenharmony_ci		if (err == 0) {
17248c2ecf20Sopenharmony_ci			if (transport->xprt.reuseport)
17258c2ecf20Sopenharmony_ci				transport->srcport = port;
17268c2ecf20Sopenharmony_ci			break;
17278c2ecf20Sopenharmony_ci		}
17288c2ecf20Sopenharmony_ci		last = port;
17298c2ecf20Sopenharmony_ci		port = xs_next_srcport(transport, port);
17308c2ecf20Sopenharmony_ci		if (port > last)
17318c2ecf20Sopenharmony_ci			nloop++;
17328c2ecf20Sopenharmony_ci	} while (err == -EADDRINUSE && nloop != 2);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	if (myaddr.ss_family == AF_INET)
17358c2ecf20Sopenharmony_ci		dprintk("RPC:       %s %pI4:%u: %s (%d)\n", __func__,
17368c2ecf20Sopenharmony_ci				&((struct sockaddr_in *)&myaddr)->sin_addr,
17378c2ecf20Sopenharmony_ci				port, err ? "failed" : "ok", err);
17388c2ecf20Sopenharmony_ci	else
17398c2ecf20Sopenharmony_ci		dprintk("RPC:       %s %pI6:%u: %s (%d)\n", __func__,
17408c2ecf20Sopenharmony_ci				&((struct sockaddr_in6 *)&myaddr)->sin6_addr,
17418c2ecf20Sopenharmony_ci				port, err ? "failed" : "ok", err);
17428c2ecf20Sopenharmony_ci	return err;
17438c2ecf20Sopenharmony_ci}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci/*
17468c2ecf20Sopenharmony_ci * We don't support autobind on AF_LOCAL sockets
17478c2ecf20Sopenharmony_ci */
17488c2ecf20Sopenharmony_cistatic void xs_local_rpcbind(struct rpc_task *task)
17498c2ecf20Sopenharmony_ci{
17508c2ecf20Sopenharmony_ci	xprt_set_bound(task->tk_xprt);
17518c2ecf20Sopenharmony_ci}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_cistatic void xs_local_set_port(struct rpc_xprt *xprt, unsigned short port)
17548c2ecf20Sopenharmony_ci{
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC
17588c2ecf20Sopenharmony_cistatic struct lock_class_key xs_key[2];
17598c2ecf20Sopenharmony_cistatic struct lock_class_key xs_slock_key[2];
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cistatic inline void xs_reclassify_socketu(struct socket *sock)
17628c2ecf20Sopenharmony_ci{
17638c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC",
17668c2ecf20Sopenharmony_ci		&xs_slock_key[1], "sk_lock-AF_LOCAL-RPC", &xs_key[1]);
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_cistatic inline void xs_reclassify_socket4(struct socket *sock)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
17748c2ecf20Sopenharmony_ci		&xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
17758c2ecf20Sopenharmony_ci}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_cistatic inline void xs_reclassify_socket6(struct socket *sock)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
17828c2ecf20Sopenharmony_ci		&xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
17838c2ecf20Sopenharmony_ci}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_cistatic inline void xs_reclassify_socket(int family, struct socket *sock)
17868c2ecf20Sopenharmony_ci{
17878c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!sock_allow_reclassification(sock->sk)))
17888c2ecf20Sopenharmony_ci		return;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	switch (family) {
17918c2ecf20Sopenharmony_ci	case AF_LOCAL:
17928c2ecf20Sopenharmony_ci		xs_reclassify_socketu(sock);
17938c2ecf20Sopenharmony_ci		break;
17948c2ecf20Sopenharmony_ci	case AF_INET:
17958c2ecf20Sopenharmony_ci		xs_reclassify_socket4(sock);
17968c2ecf20Sopenharmony_ci		break;
17978c2ecf20Sopenharmony_ci	case AF_INET6:
17988c2ecf20Sopenharmony_ci		xs_reclassify_socket6(sock);
17998c2ecf20Sopenharmony_ci		break;
18008c2ecf20Sopenharmony_ci	}
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci#else
18038c2ecf20Sopenharmony_cistatic inline void xs_reclassify_socket(int family, struct socket *sock)
18048c2ecf20Sopenharmony_ci{
18058c2ecf20Sopenharmony_ci}
18068c2ecf20Sopenharmony_ci#endif
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_cistatic void xs_dummy_setup_socket(struct work_struct *work)
18098c2ecf20Sopenharmony_ci{
18108c2ecf20Sopenharmony_ci}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_cistatic struct socket *xs_create_sock(struct rpc_xprt *xprt,
18138c2ecf20Sopenharmony_ci		struct sock_xprt *transport, int family, int type,
18148c2ecf20Sopenharmony_ci		int protocol, bool reuseport)
18158c2ecf20Sopenharmony_ci{
18168c2ecf20Sopenharmony_ci	struct file *filp;
18178c2ecf20Sopenharmony_ci	struct socket *sock;
18188c2ecf20Sopenharmony_ci	int err;
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	err = __sock_create(xprt->xprt_net, family, type, protocol, &sock, 1);
18218c2ecf20Sopenharmony_ci	if (err < 0) {
18228c2ecf20Sopenharmony_ci		dprintk("RPC:       can't create %d transport socket (%d).\n",
18238c2ecf20Sopenharmony_ci				protocol, -err);
18248c2ecf20Sopenharmony_ci		goto out;
18258c2ecf20Sopenharmony_ci	}
18268c2ecf20Sopenharmony_ci	xs_reclassify_socket(family, sock);
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	if (reuseport)
18298c2ecf20Sopenharmony_ci		sock_set_reuseport(sock->sk);
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	err = xs_bind(transport, sock);
18328c2ecf20Sopenharmony_ci	if (err) {
18338c2ecf20Sopenharmony_ci		sock_release(sock);
18348c2ecf20Sopenharmony_ci		goto out;
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
18388c2ecf20Sopenharmony_ci	if (IS_ERR(filp))
18398c2ecf20Sopenharmony_ci		return ERR_CAST(filp);
18408c2ecf20Sopenharmony_ci	transport->file = filp;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	return sock;
18438c2ecf20Sopenharmony_ciout:
18448c2ecf20Sopenharmony_ci	return ERR_PTR(err);
18458c2ecf20Sopenharmony_ci}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_cistatic int xs_local_finish_connecting(struct rpc_xprt *xprt,
18488c2ecf20Sopenharmony_ci				      struct socket *sock)
18498c2ecf20Sopenharmony_ci{
18508c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt,
18518c2ecf20Sopenharmony_ci									xprt);
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	if (!transport->inet) {
18548c2ecf20Sopenharmony_ci		struct sock *sk = sock->sk;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci		write_lock_bh(&sk->sk_callback_lock);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		xs_save_old_callbacks(transport, sk);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		sk->sk_user_data = xprt;
18618c2ecf20Sopenharmony_ci		sk->sk_data_ready = xs_data_ready;
18628c2ecf20Sopenharmony_ci		sk->sk_write_space = xs_udp_write_space;
18638c2ecf20Sopenharmony_ci		sock_set_flag(sk, SOCK_FASYNC);
18648c2ecf20Sopenharmony_ci		sk->sk_error_report = xs_error_report;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci		xprt_clear_connected(xprt);
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci		/* Reset to new socket */
18698c2ecf20Sopenharmony_ci		transport->sock = sock;
18708c2ecf20Sopenharmony_ci		transport->inet = sk;
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci		write_unlock_bh(&sk->sk_callback_lock);
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	xs_stream_start_connect(transport);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, 0);
18788c2ecf20Sopenharmony_ci}
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci/**
18818c2ecf20Sopenharmony_ci * xs_local_setup_socket - create AF_LOCAL socket, connect to a local endpoint
18828c2ecf20Sopenharmony_ci * @transport: socket transport to connect
18838c2ecf20Sopenharmony_ci */
18848c2ecf20Sopenharmony_cistatic int xs_local_setup_socket(struct sock_xprt *transport)
18858c2ecf20Sopenharmony_ci{
18868c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
18878c2ecf20Sopenharmony_ci	struct file *filp;
18888c2ecf20Sopenharmony_ci	struct socket *sock;
18898c2ecf20Sopenharmony_ci	int status;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	status = __sock_create(xprt->xprt_net, AF_LOCAL,
18928c2ecf20Sopenharmony_ci					SOCK_STREAM, 0, &sock, 1);
18938c2ecf20Sopenharmony_ci	if (status < 0) {
18948c2ecf20Sopenharmony_ci		dprintk("RPC:       can't create AF_LOCAL "
18958c2ecf20Sopenharmony_ci			"transport socket (%d).\n", -status);
18968c2ecf20Sopenharmony_ci		goto out;
18978c2ecf20Sopenharmony_ci	}
18988c2ecf20Sopenharmony_ci	xs_reclassify_socket(AF_LOCAL, sock);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
19018c2ecf20Sopenharmony_ci	if (IS_ERR(filp)) {
19028c2ecf20Sopenharmony_ci		status = PTR_ERR(filp);
19038c2ecf20Sopenharmony_ci		goto out;
19048c2ecf20Sopenharmony_ci	}
19058c2ecf20Sopenharmony_ci	transport->file = filp;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	dprintk("RPC:       worker connecting xprt %p via AF_LOCAL to %s\n",
19088c2ecf20Sopenharmony_ci			xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	status = xs_local_finish_connecting(xprt, sock);
19118c2ecf20Sopenharmony_ci	trace_rpc_socket_connect(xprt, sock, status);
19128c2ecf20Sopenharmony_ci	switch (status) {
19138c2ecf20Sopenharmony_ci	case 0:
19148c2ecf20Sopenharmony_ci		dprintk("RPC:       xprt %p connected to %s\n",
19158c2ecf20Sopenharmony_ci				xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
19168c2ecf20Sopenharmony_ci		xprt->stat.connect_count++;
19178c2ecf20Sopenharmony_ci		xprt->stat.connect_time += (long)jiffies -
19188c2ecf20Sopenharmony_ci					   xprt->stat.connect_start;
19198c2ecf20Sopenharmony_ci		xprt_set_connected(xprt);
19208c2ecf20Sopenharmony_ci		break;
19218c2ecf20Sopenharmony_ci	case -ENOBUFS:
19228c2ecf20Sopenharmony_ci		break;
19238c2ecf20Sopenharmony_ci	case -ENOENT:
19248c2ecf20Sopenharmony_ci		dprintk("RPC:       xprt %p: socket %s does not exist\n",
19258c2ecf20Sopenharmony_ci				xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
19268c2ecf20Sopenharmony_ci		break;
19278c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
19288c2ecf20Sopenharmony_ci		dprintk("RPC:       xprt %p: connection refused for %s\n",
19298c2ecf20Sopenharmony_ci				xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
19308c2ecf20Sopenharmony_ci		break;
19318c2ecf20Sopenharmony_ci	default:
19328c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: unhandled error (%d) connecting to %s\n",
19338c2ecf20Sopenharmony_ci				__func__, -status,
19348c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_ADDR]);
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ciout:
19388c2ecf20Sopenharmony_ci	xprt_clear_connecting(xprt);
19398c2ecf20Sopenharmony_ci	xprt_wake_pending_tasks(xprt, status);
19408c2ecf20Sopenharmony_ci	return status;
19418c2ecf20Sopenharmony_ci}
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_cistatic void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
19468c2ecf20Sopenharmony_ci	int ret;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	 if (RPC_IS_ASYNC(task)) {
19498c2ecf20Sopenharmony_ci		/*
19508c2ecf20Sopenharmony_ci		 * We want the AF_LOCAL connect to be resolved in the
19518c2ecf20Sopenharmony_ci		 * filesystem namespace of the process making the rpc
19528c2ecf20Sopenharmony_ci		 * call.  Thus we connect synchronously.
19538c2ecf20Sopenharmony_ci		 *
19548c2ecf20Sopenharmony_ci		 * If we want to support asynchronous AF_LOCAL calls,
19558c2ecf20Sopenharmony_ci		 * we'll need to figure out how to pass a namespace to
19568c2ecf20Sopenharmony_ci		 * connect.
19578c2ecf20Sopenharmony_ci		 */
19588c2ecf20Sopenharmony_ci		task->tk_rpc_status = -ENOTCONN;
19598c2ecf20Sopenharmony_ci		rpc_exit(task, -ENOTCONN);
19608c2ecf20Sopenharmony_ci		return;
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci	ret = xs_local_setup_socket(transport);
19638c2ecf20Sopenharmony_ci	if (ret && !RPC_IS_SOFTCONN(task))
19648c2ecf20Sopenharmony_ci		msleep_interruptible(15000);
19658c2ecf20Sopenharmony_ci}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
19688c2ecf20Sopenharmony_ci/*
19698c2ecf20Sopenharmony_ci * Note that this should be called with XPRT_LOCKED held (or when we otherwise
19708c2ecf20Sopenharmony_ci * know that we have exclusive access to the socket), to guard against
19718c2ecf20Sopenharmony_ci * races with xs_reset_transport.
19728c2ecf20Sopenharmony_ci */
19738c2ecf20Sopenharmony_cistatic void xs_set_memalloc(struct rpc_xprt *xprt)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt,
19768c2ecf20Sopenharmony_ci			xprt);
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	/*
19798c2ecf20Sopenharmony_ci	 * If there's no sock, then we have nothing to set. The
19808c2ecf20Sopenharmony_ci	 * reconnecting process will get it for us.
19818c2ecf20Sopenharmony_ci	 */
19828c2ecf20Sopenharmony_ci	if (!transport->inet)
19838c2ecf20Sopenharmony_ci		return;
19848c2ecf20Sopenharmony_ci	if (atomic_read(&xprt->swapper))
19858c2ecf20Sopenharmony_ci		sk_set_memalloc(transport->inet);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci/**
19898c2ecf20Sopenharmony_ci * xs_enable_swap - Tag this transport as being used for swap.
19908c2ecf20Sopenharmony_ci * @xprt: transport to tag
19918c2ecf20Sopenharmony_ci *
19928c2ecf20Sopenharmony_ci * Take a reference to this transport on behalf of the rpc_clnt, and
19938c2ecf20Sopenharmony_ci * optionally mark it for swapping if it wasn't already.
19948c2ecf20Sopenharmony_ci */
19958c2ecf20Sopenharmony_cistatic int
19968c2ecf20Sopenharmony_cixs_enable_swap(struct rpc_xprt *xprt)
19978c2ecf20Sopenharmony_ci{
19988c2ecf20Sopenharmony_ci	struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt);
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	if (atomic_inc_return(&xprt->swapper) != 1)
20018c2ecf20Sopenharmony_ci		return 0;
20028c2ecf20Sopenharmony_ci	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE))
20038c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
20048c2ecf20Sopenharmony_ci	if (xs->inet)
20058c2ecf20Sopenharmony_ci		sk_set_memalloc(xs->inet);
20068c2ecf20Sopenharmony_ci	xprt_release_xprt(xprt, NULL);
20078c2ecf20Sopenharmony_ci	return 0;
20088c2ecf20Sopenharmony_ci}
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci/**
20118c2ecf20Sopenharmony_ci * xs_disable_swap - Untag this transport as being used for swap.
20128c2ecf20Sopenharmony_ci * @xprt: transport to tag
20138c2ecf20Sopenharmony_ci *
20148c2ecf20Sopenharmony_ci * Drop a "swapper" reference to this xprt on behalf of the rpc_clnt. If the
20158c2ecf20Sopenharmony_ci * swapper refcount goes to 0, untag the socket as a memalloc socket.
20168c2ecf20Sopenharmony_ci */
20178c2ecf20Sopenharmony_cistatic void
20188c2ecf20Sopenharmony_cixs_disable_swap(struct rpc_xprt *xprt)
20198c2ecf20Sopenharmony_ci{
20208c2ecf20Sopenharmony_ci	struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	if (!atomic_dec_and_test(&xprt->swapper))
20238c2ecf20Sopenharmony_ci		return;
20248c2ecf20Sopenharmony_ci	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE))
20258c2ecf20Sopenharmony_ci		return;
20268c2ecf20Sopenharmony_ci	if (xs->inet)
20278c2ecf20Sopenharmony_ci		sk_clear_memalloc(xs->inet);
20288c2ecf20Sopenharmony_ci	xprt_release_xprt(xprt, NULL);
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci#else
20318c2ecf20Sopenharmony_cistatic void xs_set_memalloc(struct rpc_xprt *xprt)
20328c2ecf20Sopenharmony_ci{
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic int
20368c2ecf20Sopenharmony_cixs_enable_swap(struct rpc_xprt *xprt)
20378c2ecf20Sopenharmony_ci{
20388c2ecf20Sopenharmony_ci	return -EINVAL;
20398c2ecf20Sopenharmony_ci}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_cistatic void
20428c2ecf20Sopenharmony_cixs_disable_swap(struct rpc_xprt *xprt)
20438c2ecf20Sopenharmony_ci{
20448c2ecf20Sopenharmony_ci}
20458c2ecf20Sopenharmony_ci#endif
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_cistatic void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (!transport->inet) {
20528c2ecf20Sopenharmony_ci		struct sock *sk = sock->sk;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		write_lock_bh(&sk->sk_callback_lock);
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci		xs_save_old_callbacks(transport, sk);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci		sk->sk_user_data = xprt;
20598c2ecf20Sopenharmony_ci		sk->sk_data_ready = xs_data_ready;
20608c2ecf20Sopenharmony_ci		sk->sk_write_space = xs_udp_write_space;
20618c2ecf20Sopenharmony_ci		sock_set_flag(sk, SOCK_FASYNC);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci		xprt_set_connected(xprt);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		/* Reset to new socket */
20668c2ecf20Sopenharmony_ci		transport->sock = sock;
20678c2ecf20Sopenharmony_ci		transport->inet = sk;
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci		xs_set_memalloc(xprt);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci		write_unlock_bh(&sk->sk_callback_lock);
20728c2ecf20Sopenharmony_ci	}
20738c2ecf20Sopenharmony_ci	xs_udp_do_set_buffer_size(xprt);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	xprt->stat.connect_start = jiffies;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_cistatic void xs_udp_setup_socket(struct work_struct *work)
20798c2ecf20Sopenharmony_ci{
20808c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
20818c2ecf20Sopenharmony_ci		container_of(work, struct sock_xprt, connect_worker.work);
20828c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
20838c2ecf20Sopenharmony_ci	struct socket *sock;
20848c2ecf20Sopenharmony_ci	int status = -EIO;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	sock = xs_create_sock(xprt, transport,
20878c2ecf20Sopenharmony_ci			xs_addr(xprt)->sa_family, SOCK_DGRAM,
20888c2ecf20Sopenharmony_ci			IPPROTO_UDP, false);
20898c2ecf20Sopenharmony_ci	if (IS_ERR(sock))
20908c2ecf20Sopenharmony_ci		goto out;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	dprintk("RPC:       worker connecting xprt %p via %s to "
20938c2ecf20Sopenharmony_ci				"%s (port %s)\n", xprt,
20948c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PROTO],
20958c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_ADDR],
20968c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PORT]);
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	xs_udp_finish_connecting(xprt, sock);
20998c2ecf20Sopenharmony_ci	trace_rpc_socket_connect(xprt, sock, 0);
21008c2ecf20Sopenharmony_ci	status = 0;
21018c2ecf20Sopenharmony_ciout:
21028c2ecf20Sopenharmony_ci	xprt_clear_connecting(xprt);
21038c2ecf20Sopenharmony_ci	xprt_unlock_connect(xprt, transport);
21048c2ecf20Sopenharmony_ci	xprt_wake_pending_tasks(xprt, status);
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci/**
21088c2ecf20Sopenharmony_ci * xs_tcp_shutdown - gracefully shut down a TCP socket
21098c2ecf20Sopenharmony_ci * @xprt: transport
21108c2ecf20Sopenharmony_ci *
21118c2ecf20Sopenharmony_ci * Initiates a graceful shutdown of the TCP socket by calling the
21128c2ecf20Sopenharmony_ci * equivalent of shutdown(SHUT_RDWR);
21138c2ecf20Sopenharmony_ci */
21148c2ecf20Sopenharmony_cistatic void xs_tcp_shutdown(struct rpc_xprt *xprt)
21158c2ecf20Sopenharmony_ci{
21168c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
21178c2ecf20Sopenharmony_ci	struct socket *sock = transport->sock;
21188c2ecf20Sopenharmony_ci	int skst = transport->inet ? transport->inet->sk_state : TCP_CLOSE;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	if (sock == NULL)
21218c2ecf20Sopenharmony_ci		return;
21228c2ecf20Sopenharmony_ci	switch (skst) {
21238c2ecf20Sopenharmony_ci	default:
21248c2ecf20Sopenharmony_ci		kernel_sock_shutdown(sock, SHUT_RDWR);
21258c2ecf20Sopenharmony_ci		trace_rpc_socket_shutdown(xprt, sock);
21268c2ecf20Sopenharmony_ci		break;
21278c2ecf20Sopenharmony_ci	case TCP_CLOSE:
21288c2ecf20Sopenharmony_ci	case TCP_TIME_WAIT:
21298c2ecf20Sopenharmony_ci		xs_reset_transport(transport);
21308c2ecf20Sopenharmony_ci	}
21318c2ecf20Sopenharmony_ci}
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_cistatic void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
21348c2ecf20Sopenharmony_ci		struct socket *sock)
21358c2ecf20Sopenharmony_ci{
21368c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
21378c2ecf20Sopenharmony_ci	unsigned int keepidle;
21388c2ecf20Sopenharmony_ci	unsigned int keepcnt;
21398c2ecf20Sopenharmony_ci	unsigned int timeo;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	spin_lock(&xprt->transport_lock);
21428c2ecf20Sopenharmony_ci	keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ);
21438c2ecf20Sopenharmony_ci	keepcnt = xprt->timeout->to_retries + 1;
21448c2ecf20Sopenharmony_ci	timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
21458c2ecf20Sopenharmony_ci		(xprt->timeout->to_retries + 1);
21468c2ecf20Sopenharmony_ci	clear_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
21478c2ecf20Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	/* TCP Keepalive options */
21508c2ecf20Sopenharmony_ci	sock_set_keepalive(sock->sk);
21518c2ecf20Sopenharmony_ci	tcp_sock_set_keepidle(sock->sk, keepidle);
21528c2ecf20Sopenharmony_ci	tcp_sock_set_keepintvl(sock->sk, keepidle);
21538c2ecf20Sopenharmony_ci	tcp_sock_set_keepcnt(sock->sk, keepcnt);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	/* TCP user timeout (see RFC5482) */
21568c2ecf20Sopenharmony_ci	tcp_sock_set_user_timeout(sock->sk, timeo);
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_cistatic void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt,
21608c2ecf20Sopenharmony_ci		unsigned long connect_timeout,
21618c2ecf20Sopenharmony_ci		unsigned long reconnect_timeout)
21628c2ecf20Sopenharmony_ci{
21638c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
21648c2ecf20Sopenharmony_ci	struct rpc_timeout to;
21658c2ecf20Sopenharmony_ci	unsigned long initval;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	spin_lock(&xprt->transport_lock);
21688c2ecf20Sopenharmony_ci	if (reconnect_timeout < xprt->max_reconnect_timeout)
21698c2ecf20Sopenharmony_ci		xprt->max_reconnect_timeout = reconnect_timeout;
21708c2ecf20Sopenharmony_ci	if (connect_timeout < xprt->connect_timeout) {
21718c2ecf20Sopenharmony_ci		memcpy(&to, xprt->timeout, sizeof(to));
21728c2ecf20Sopenharmony_ci		initval = DIV_ROUND_UP(connect_timeout, to.to_retries + 1);
21738c2ecf20Sopenharmony_ci		/* Arbitrary lower limit */
21748c2ecf20Sopenharmony_ci		if (initval <  XS_TCP_INIT_REEST_TO << 1)
21758c2ecf20Sopenharmony_ci			initval = XS_TCP_INIT_REEST_TO << 1;
21768c2ecf20Sopenharmony_ci		to.to_initval = initval;
21778c2ecf20Sopenharmony_ci		to.to_maxval = initval;
21788c2ecf20Sopenharmony_ci		memcpy(&transport->tcp_timeout, &to,
21798c2ecf20Sopenharmony_ci				sizeof(transport->tcp_timeout));
21808c2ecf20Sopenharmony_ci		xprt->timeout = &transport->tcp_timeout;
21818c2ecf20Sopenharmony_ci		xprt->connect_timeout = connect_timeout;
21828c2ecf20Sopenharmony_ci	}
21838c2ecf20Sopenharmony_ci	set_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
21848c2ecf20Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
21858c2ecf20Sopenharmony_ci}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_cistatic int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
21888c2ecf20Sopenharmony_ci{
21898c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
21908c2ecf20Sopenharmony_ci	int ret = -ENOTCONN;
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	if (!transport->inet) {
21938c2ecf20Sopenharmony_ci		struct sock *sk = sock->sk;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci		/* Avoid temporary address, they are bad for long-lived
21968c2ecf20Sopenharmony_ci		 * connections such as NFS mounts.
21978c2ecf20Sopenharmony_ci		 * RFC4941, section 3.6 suggests that:
21988c2ecf20Sopenharmony_ci		 *    Individual applications, which have specific
21998c2ecf20Sopenharmony_ci		 *    knowledge about the normal duration of connections,
22008c2ecf20Sopenharmony_ci		 *    MAY override this as appropriate.
22018c2ecf20Sopenharmony_ci		 */
22028c2ecf20Sopenharmony_ci		if (xs_addr(xprt)->sa_family == PF_INET6) {
22038c2ecf20Sopenharmony_ci			ip6_sock_set_addr_preferences(sk,
22048c2ecf20Sopenharmony_ci				IPV6_PREFER_SRC_PUBLIC);
22058c2ecf20Sopenharmony_ci		}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci		xs_tcp_set_socket_timeouts(xprt, sock);
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci		write_lock_bh(&sk->sk_callback_lock);
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci		xs_save_old_callbacks(transport, sk);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		sk->sk_user_data = xprt;
22148c2ecf20Sopenharmony_ci		sk->sk_data_ready = xs_data_ready;
22158c2ecf20Sopenharmony_ci		sk->sk_state_change = xs_tcp_state_change;
22168c2ecf20Sopenharmony_ci		sk->sk_write_space = xs_tcp_write_space;
22178c2ecf20Sopenharmony_ci		sock_set_flag(sk, SOCK_FASYNC);
22188c2ecf20Sopenharmony_ci		sk->sk_error_report = xs_error_report;
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci		/* socket options */
22218c2ecf20Sopenharmony_ci		sock_reset_flag(sk, SOCK_LINGER);
22228c2ecf20Sopenharmony_ci		tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci		xprt_clear_connected(xprt);
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci		/* Reset to new socket */
22278c2ecf20Sopenharmony_ci		transport->sock = sock;
22288c2ecf20Sopenharmony_ci		transport->inet = sk;
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci		write_unlock_bh(&sk->sk_callback_lock);
22318c2ecf20Sopenharmony_ci	}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	if (!xprt_bound(xprt))
22348c2ecf20Sopenharmony_ci		goto out;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	xs_set_memalloc(xprt);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	xs_stream_start_connect(transport);
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	/* Tell the socket layer to start connecting... */
22418c2ecf20Sopenharmony_ci	set_bit(XPRT_SOCK_CONNECTING, &transport->sock_state);
22428c2ecf20Sopenharmony_ci	ret = kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
22438c2ecf20Sopenharmony_ci	switch (ret) {
22448c2ecf20Sopenharmony_ci	case 0:
22458c2ecf20Sopenharmony_ci		xs_set_srcport(transport, sock);
22468c2ecf20Sopenharmony_ci		fallthrough;
22478c2ecf20Sopenharmony_ci	case -EINPROGRESS:
22488c2ecf20Sopenharmony_ci		/* SYN_SENT! */
22498c2ecf20Sopenharmony_ci		if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
22508c2ecf20Sopenharmony_ci			xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
22518c2ecf20Sopenharmony_ci		break;
22528c2ecf20Sopenharmony_ci	case -EADDRNOTAVAIL:
22538c2ecf20Sopenharmony_ci		/* Source port number is unavailable. Try a new one! */
22548c2ecf20Sopenharmony_ci		transport->srcport = 0;
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ciout:
22578c2ecf20Sopenharmony_ci	return ret;
22588c2ecf20Sopenharmony_ci}
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci/**
22618c2ecf20Sopenharmony_ci * xs_tcp_setup_socket - create a TCP socket and connect to a remote endpoint
22628c2ecf20Sopenharmony_ci * @work: queued work item
22638c2ecf20Sopenharmony_ci *
22648c2ecf20Sopenharmony_ci * Invoked by a work queue tasklet.
22658c2ecf20Sopenharmony_ci */
22668c2ecf20Sopenharmony_cistatic void xs_tcp_setup_socket(struct work_struct *work)
22678c2ecf20Sopenharmony_ci{
22688c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
22698c2ecf20Sopenharmony_ci		container_of(work, struct sock_xprt, connect_worker.work);
22708c2ecf20Sopenharmony_ci	struct socket *sock = transport->sock;
22718c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = &transport->xprt;
22728c2ecf20Sopenharmony_ci	int status = -EIO;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	if (xprt_connected(xprt))
22758c2ecf20Sopenharmony_ci		goto out;
22768c2ecf20Sopenharmony_ci	if (test_and_clear_bit(XPRT_SOCK_CONNECT_SENT,
22778c2ecf20Sopenharmony_ci			       &transport->sock_state) ||
22788c2ecf20Sopenharmony_ci	    !sock) {
22798c2ecf20Sopenharmony_ci		xs_reset_transport(transport);
22808c2ecf20Sopenharmony_ci		sock = xs_create_sock(xprt, transport, xs_addr(xprt)->sa_family,
22818c2ecf20Sopenharmony_ci				      SOCK_STREAM, IPPROTO_TCP, true);
22828c2ecf20Sopenharmony_ci		if (IS_ERR(sock)) {
22838c2ecf20Sopenharmony_ci			status = PTR_ERR(sock);
22848c2ecf20Sopenharmony_ci			goto out;
22858c2ecf20Sopenharmony_ci		}
22868c2ecf20Sopenharmony_ci	}
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	dprintk("RPC:       worker connecting xprt %p via %s to "
22898c2ecf20Sopenharmony_ci				"%s (port %s)\n", xprt,
22908c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PROTO],
22918c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_ADDR],
22928c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PORT]);
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	status = xs_tcp_finish_connecting(xprt, sock);
22958c2ecf20Sopenharmony_ci	trace_rpc_socket_connect(xprt, sock, status);
22968c2ecf20Sopenharmony_ci	dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
22978c2ecf20Sopenharmony_ci			xprt, -status, xprt_connected(xprt),
22988c2ecf20Sopenharmony_ci			sock->sk->sk_state);
22998c2ecf20Sopenharmony_ci	switch (status) {
23008c2ecf20Sopenharmony_ci	default:
23018c2ecf20Sopenharmony_ci		printk("%s: connect returned unhandled error %d\n",
23028c2ecf20Sopenharmony_ci			__func__, status);
23038c2ecf20Sopenharmony_ci		fallthrough;
23048c2ecf20Sopenharmony_ci	case -EADDRNOTAVAIL:
23058c2ecf20Sopenharmony_ci		/* We're probably in TIME_WAIT. Get rid of existing socket,
23068c2ecf20Sopenharmony_ci		 * and retry
23078c2ecf20Sopenharmony_ci		 */
23088c2ecf20Sopenharmony_ci		xs_tcp_force_close(xprt);
23098c2ecf20Sopenharmony_ci		break;
23108c2ecf20Sopenharmony_ci	case 0:
23118c2ecf20Sopenharmony_ci	case -EINPROGRESS:
23128c2ecf20Sopenharmony_ci		set_bit(XPRT_SOCK_CONNECT_SENT, &transport->sock_state);
23138c2ecf20Sopenharmony_ci		fallthrough;
23148c2ecf20Sopenharmony_ci	case -EALREADY:
23158c2ecf20Sopenharmony_ci		xprt_unlock_connect(xprt, transport);
23168c2ecf20Sopenharmony_ci		return;
23178c2ecf20Sopenharmony_ci	case -EINVAL:
23188c2ecf20Sopenharmony_ci		/* Happens, for instance, if the user specified a link
23198c2ecf20Sopenharmony_ci		 * local IPv6 address without a scope-id.
23208c2ecf20Sopenharmony_ci		 */
23218c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
23228c2ecf20Sopenharmony_ci	case -ECONNRESET:
23238c2ecf20Sopenharmony_ci	case -ENETDOWN:
23248c2ecf20Sopenharmony_ci	case -ENETUNREACH:
23258c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
23268c2ecf20Sopenharmony_ci	case -EADDRINUSE:
23278c2ecf20Sopenharmony_ci	case -ENOBUFS:
23288c2ecf20Sopenharmony_ci		/*
23298c2ecf20Sopenharmony_ci		 * xs_tcp_force_close() wakes tasks with -EIO.
23308c2ecf20Sopenharmony_ci		 * We need to wake them first to ensure the
23318c2ecf20Sopenharmony_ci		 * correct error code.
23328c2ecf20Sopenharmony_ci		 */
23338c2ecf20Sopenharmony_ci		xprt_wake_pending_tasks(xprt, status);
23348c2ecf20Sopenharmony_ci		xs_tcp_force_close(xprt);
23358c2ecf20Sopenharmony_ci		goto out;
23368c2ecf20Sopenharmony_ci	}
23378c2ecf20Sopenharmony_ci	status = -EAGAIN;
23388c2ecf20Sopenharmony_ciout:
23398c2ecf20Sopenharmony_ci	xprt_clear_connecting(xprt);
23408c2ecf20Sopenharmony_ci	xprt_unlock_connect(xprt, transport);
23418c2ecf20Sopenharmony_ci	xprt_wake_pending_tasks(xprt, status);
23428c2ecf20Sopenharmony_ci}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci/**
23458c2ecf20Sopenharmony_ci * xs_connect - connect a socket to a remote endpoint
23468c2ecf20Sopenharmony_ci * @xprt: pointer to transport structure
23478c2ecf20Sopenharmony_ci * @task: address of RPC task that manages state of connect request
23488c2ecf20Sopenharmony_ci *
23498c2ecf20Sopenharmony_ci * TCP: If the remote end dropped the connection, delay reconnecting.
23508c2ecf20Sopenharmony_ci *
23518c2ecf20Sopenharmony_ci * UDP socket connects are synchronous, but we use a work queue anyway
23528c2ecf20Sopenharmony_ci * to guarantee that even unprivileged user processes can set up a
23538c2ecf20Sopenharmony_ci * socket on a privileged port.
23548c2ecf20Sopenharmony_ci *
23558c2ecf20Sopenharmony_ci * If a UDP socket connect fails, the delay behavior here prevents
23568c2ecf20Sopenharmony_ci * retry floods (hard mounts).
23578c2ecf20Sopenharmony_ci */
23588c2ecf20Sopenharmony_cistatic void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
23598c2ecf20Sopenharmony_ci{
23608c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
23618c2ecf20Sopenharmony_ci	unsigned long delay = 0;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport));
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	if (transport->sock != NULL) {
23668c2ecf20Sopenharmony_ci		dprintk("RPC:       xs_connect delayed xprt %p for %lu "
23678c2ecf20Sopenharmony_ci			"seconds\n", xprt, xprt->reestablish_timeout / HZ);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci		delay = xprt_reconnect_delay(xprt);
23708c2ecf20Sopenharmony_ci		xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO);
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	} else
23738c2ecf20Sopenharmony_ci		dprintk("RPC:       xs_connect scheduled xprt %p\n", xprt);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	queue_delayed_work(xprtiod_workqueue,
23768c2ecf20Sopenharmony_ci			&transport->connect_worker,
23778c2ecf20Sopenharmony_ci			delay);
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic void xs_wake_disconnect(struct sock_xprt *transport)
23818c2ecf20Sopenharmony_ci{
23828c2ecf20Sopenharmony_ci	if (test_and_clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state))
23838c2ecf20Sopenharmony_ci		xs_tcp_force_close(&transport->xprt);
23848c2ecf20Sopenharmony_ci}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_cistatic void xs_wake_write(struct sock_xprt *transport)
23878c2ecf20Sopenharmony_ci{
23888c2ecf20Sopenharmony_ci	if (test_and_clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state))
23898c2ecf20Sopenharmony_ci		xprt_write_space(&transport->xprt);
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_cistatic void xs_wake_error(struct sock_xprt *transport)
23938c2ecf20Sopenharmony_ci{
23948c2ecf20Sopenharmony_ci	int sockerr;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	if (!test_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
23978c2ecf20Sopenharmony_ci		return;
23988c2ecf20Sopenharmony_ci	mutex_lock(&transport->recv_mutex);
23998c2ecf20Sopenharmony_ci	if (transport->sock == NULL)
24008c2ecf20Sopenharmony_ci		goto out;
24018c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
24028c2ecf20Sopenharmony_ci		goto out;
24038c2ecf20Sopenharmony_ci	sockerr = xchg(&transport->xprt_err, 0);
24048c2ecf20Sopenharmony_ci	if (sockerr < 0)
24058c2ecf20Sopenharmony_ci		xprt_wake_pending_tasks(&transport->xprt, sockerr);
24068c2ecf20Sopenharmony_ciout:
24078c2ecf20Sopenharmony_ci	mutex_unlock(&transport->recv_mutex);
24088c2ecf20Sopenharmony_ci}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_cistatic void xs_wake_pending(struct sock_xprt *transport)
24118c2ecf20Sopenharmony_ci{
24128c2ecf20Sopenharmony_ci	if (test_and_clear_bit(XPRT_SOCK_WAKE_PENDING, &transport->sock_state))
24138c2ecf20Sopenharmony_ci		xprt_wake_pending_tasks(&transport->xprt, -EAGAIN);
24148c2ecf20Sopenharmony_ci}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_cistatic void xs_error_handle(struct work_struct *work)
24178c2ecf20Sopenharmony_ci{
24188c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(work,
24198c2ecf20Sopenharmony_ci			struct sock_xprt, error_worker);
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	xs_wake_disconnect(transport);
24228c2ecf20Sopenharmony_ci	xs_wake_write(transport);
24238c2ecf20Sopenharmony_ci	xs_wake_error(transport);
24248c2ecf20Sopenharmony_ci	xs_wake_pending(transport);
24258c2ecf20Sopenharmony_ci}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci/**
24288c2ecf20Sopenharmony_ci * xs_local_print_stats - display AF_LOCAL socket-specifc stats
24298c2ecf20Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics
24308c2ecf20Sopenharmony_ci * @seq: output file
24318c2ecf20Sopenharmony_ci *
24328c2ecf20Sopenharmony_ci */
24338c2ecf20Sopenharmony_cistatic void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
24348c2ecf20Sopenharmony_ci{
24358c2ecf20Sopenharmony_ci	long idle_time = 0;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	if (xprt_connected(xprt))
24388c2ecf20Sopenharmony_ci		idle_time = (long)(jiffies - xprt->last_used) / HZ;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu "
24418c2ecf20Sopenharmony_ci			"%llu %llu %lu %llu %llu\n",
24428c2ecf20Sopenharmony_ci			xprt->stat.bind_count,
24438c2ecf20Sopenharmony_ci			xprt->stat.connect_count,
24448c2ecf20Sopenharmony_ci			xprt->stat.connect_time / HZ,
24458c2ecf20Sopenharmony_ci			idle_time,
24468c2ecf20Sopenharmony_ci			xprt->stat.sends,
24478c2ecf20Sopenharmony_ci			xprt->stat.recvs,
24488c2ecf20Sopenharmony_ci			xprt->stat.bad_xids,
24498c2ecf20Sopenharmony_ci			xprt->stat.req_u,
24508c2ecf20Sopenharmony_ci			xprt->stat.bklog_u,
24518c2ecf20Sopenharmony_ci			xprt->stat.max_slots,
24528c2ecf20Sopenharmony_ci			xprt->stat.sending_u,
24538c2ecf20Sopenharmony_ci			xprt->stat.pending_u);
24548c2ecf20Sopenharmony_ci}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci/**
24578c2ecf20Sopenharmony_ci * xs_udp_print_stats - display UDP socket-specifc stats
24588c2ecf20Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics
24598c2ecf20Sopenharmony_ci * @seq: output file
24608c2ecf20Sopenharmony_ci *
24618c2ecf20Sopenharmony_ci */
24628c2ecf20Sopenharmony_cistatic void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
24638c2ecf20Sopenharmony_ci{
24648c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu "
24678c2ecf20Sopenharmony_ci			"%lu %llu %llu\n",
24688c2ecf20Sopenharmony_ci			transport->srcport,
24698c2ecf20Sopenharmony_ci			xprt->stat.bind_count,
24708c2ecf20Sopenharmony_ci			xprt->stat.sends,
24718c2ecf20Sopenharmony_ci			xprt->stat.recvs,
24728c2ecf20Sopenharmony_ci			xprt->stat.bad_xids,
24738c2ecf20Sopenharmony_ci			xprt->stat.req_u,
24748c2ecf20Sopenharmony_ci			xprt->stat.bklog_u,
24758c2ecf20Sopenharmony_ci			xprt->stat.max_slots,
24768c2ecf20Sopenharmony_ci			xprt->stat.sending_u,
24778c2ecf20Sopenharmony_ci			xprt->stat.pending_u);
24788c2ecf20Sopenharmony_ci}
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci/**
24818c2ecf20Sopenharmony_ci * xs_tcp_print_stats - display TCP socket-specifc stats
24828c2ecf20Sopenharmony_ci * @xprt: rpc_xprt struct containing statistics
24838c2ecf20Sopenharmony_ci * @seq: output file
24848c2ecf20Sopenharmony_ci *
24858c2ecf20Sopenharmony_ci */
24868c2ecf20Sopenharmony_cistatic void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
24878c2ecf20Sopenharmony_ci{
24888c2ecf20Sopenharmony_ci	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
24898c2ecf20Sopenharmony_ci	long idle_time = 0;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	if (xprt_connected(xprt))
24928c2ecf20Sopenharmony_ci		idle_time = (long)(jiffies - xprt->last_used) / HZ;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu "
24958c2ecf20Sopenharmony_ci			"%llu %llu %lu %llu %llu\n",
24968c2ecf20Sopenharmony_ci			transport->srcport,
24978c2ecf20Sopenharmony_ci			xprt->stat.bind_count,
24988c2ecf20Sopenharmony_ci			xprt->stat.connect_count,
24998c2ecf20Sopenharmony_ci			xprt->stat.connect_time / HZ,
25008c2ecf20Sopenharmony_ci			idle_time,
25018c2ecf20Sopenharmony_ci			xprt->stat.sends,
25028c2ecf20Sopenharmony_ci			xprt->stat.recvs,
25038c2ecf20Sopenharmony_ci			xprt->stat.bad_xids,
25048c2ecf20Sopenharmony_ci			xprt->stat.req_u,
25058c2ecf20Sopenharmony_ci			xprt->stat.bklog_u,
25068c2ecf20Sopenharmony_ci			xprt->stat.max_slots,
25078c2ecf20Sopenharmony_ci			xprt->stat.sending_u,
25088c2ecf20Sopenharmony_ci			xprt->stat.pending_u);
25098c2ecf20Sopenharmony_ci}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci/*
25128c2ecf20Sopenharmony_ci * Allocate a bunch of pages for a scratch buffer for the rpc code. The reason
25138c2ecf20Sopenharmony_ci * we allocate pages instead doing a kmalloc like rpc_malloc is because we want
25148c2ecf20Sopenharmony_ci * to use the server side send routines.
25158c2ecf20Sopenharmony_ci */
25168c2ecf20Sopenharmony_cistatic int bc_malloc(struct rpc_task *task)
25178c2ecf20Sopenharmony_ci{
25188c2ecf20Sopenharmony_ci	struct rpc_rqst *rqst = task->tk_rqstp;
25198c2ecf20Sopenharmony_ci	size_t size = rqst->rq_callsize;
25208c2ecf20Sopenharmony_ci	struct page *page;
25218c2ecf20Sopenharmony_ci	struct rpc_buffer *buf;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	if (size > PAGE_SIZE - sizeof(struct rpc_buffer)) {
25248c2ecf20Sopenharmony_ci		WARN_ONCE(1, "xprtsock: large bc buffer request (size %zu)\n",
25258c2ecf20Sopenharmony_ci			  size);
25268c2ecf20Sopenharmony_ci		return -EINVAL;
25278c2ecf20Sopenharmony_ci	}
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	page = alloc_page(GFP_KERNEL);
25308c2ecf20Sopenharmony_ci	if (!page)
25318c2ecf20Sopenharmony_ci		return -ENOMEM;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	buf = page_address(page);
25348c2ecf20Sopenharmony_ci	buf->len = PAGE_SIZE;
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	rqst->rq_buffer = buf->data;
25378c2ecf20Sopenharmony_ci	rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize;
25388c2ecf20Sopenharmony_ci	return 0;
25398c2ecf20Sopenharmony_ci}
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci/*
25428c2ecf20Sopenharmony_ci * Free the space allocated in the bc_alloc routine
25438c2ecf20Sopenharmony_ci */
25448c2ecf20Sopenharmony_cistatic void bc_free(struct rpc_task *task)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	void *buffer = task->tk_rqstp->rq_buffer;
25478c2ecf20Sopenharmony_ci	struct rpc_buffer *buf;
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci	buf = container_of(buffer, struct rpc_buffer, data);
25508c2ecf20Sopenharmony_ci	free_page((unsigned long)buf);
25518c2ecf20Sopenharmony_ci}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_cistatic int bc_sendto(struct rpc_rqst *req)
25548c2ecf20Sopenharmony_ci{
25558c2ecf20Sopenharmony_ci	struct xdr_buf *xdr = &req->rq_snd_buf;
25568c2ecf20Sopenharmony_ci	struct sock_xprt *transport =
25578c2ecf20Sopenharmony_ci			container_of(req->rq_xprt, struct sock_xprt, xprt);
25588c2ecf20Sopenharmony_ci	struct msghdr msg = {
25598c2ecf20Sopenharmony_ci		.msg_flags	= 0,
25608c2ecf20Sopenharmony_ci	};
25618c2ecf20Sopenharmony_ci	rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
25628c2ecf20Sopenharmony_ci					 (u32)xdr->len);
25638c2ecf20Sopenharmony_ci	unsigned int sent = 0;
25648c2ecf20Sopenharmony_ci	int err;
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	req->rq_xtime = ktime_get();
25678c2ecf20Sopenharmony_ci	err = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, marker, &sent);
25688c2ecf20Sopenharmony_ci	xdr_free_bvec(xdr);
25698c2ecf20Sopenharmony_ci	if (err < 0 || sent != (xdr->len + sizeof(marker)))
25708c2ecf20Sopenharmony_ci		return -EAGAIN;
25718c2ecf20Sopenharmony_ci	return sent;
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci/**
25758c2ecf20Sopenharmony_ci * bc_send_request - Send a backchannel Call on a TCP socket
25768c2ecf20Sopenharmony_ci * @req: rpc_rqst containing Call message to be sent
25778c2ecf20Sopenharmony_ci *
25788c2ecf20Sopenharmony_ci * xpt_mutex ensures @rqstp's whole message is written to the socket
25798c2ecf20Sopenharmony_ci * without interruption.
25808c2ecf20Sopenharmony_ci *
25818c2ecf20Sopenharmony_ci * Return values:
25828c2ecf20Sopenharmony_ci *   %0 if the message was sent successfully
25838c2ecf20Sopenharmony_ci *   %ENOTCONN if the message was not sent
25848c2ecf20Sopenharmony_ci */
25858c2ecf20Sopenharmony_cistatic int bc_send_request(struct rpc_rqst *req)
25868c2ecf20Sopenharmony_ci{
25878c2ecf20Sopenharmony_ci	struct svc_xprt	*xprt;
25888c2ecf20Sopenharmony_ci	int len;
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	/*
25918c2ecf20Sopenharmony_ci	 * Get the server socket associated with this callback xprt
25928c2ecf20Sopenharmony_ci	 */
25938c2ecf20Sopenharmony_ci	xprt = req->rq_xprt->bc_xprt;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	/*
25968c2ecf20Sopenharmony_ci	 * Grab the mutex to serialize data as the connection is shared
25978c2ecf20Sopenharmony_ci	 * with the fore channel
25988c2ecf20Sopenharmony_ci	 */
25998c2ecf20Sopenharmony_ci	mutex_lock(&xprt->xpt_mutex);
26008c2ecf20Sopenharmony_ci	if (test_bit(XPT_DEAD, &xprt->xpt_flags))
26018c2ecf20Sopenharmony_ci		len = -ENOTCONN;
26028c2ecf20Sopenharmony_ci	else
26038c2ecf20Sopenharmony_ci		len = bc_sendto(req);
26048c2ecf20Sopenharmony_ci	mutex_unlock(&xprt->xpt_mutex);
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	if (len > 0)
26078c2ecf20Sopenharmony_ci		len = 0;
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	return len;
26108c2ecf20Sopenharmony_ci}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci/*
26138c2ecf20Sopenharmony_ci * The close routine. Since this is client initiated, we do nothing
26148c2ecf20Sopenharmony_ci */
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_cistatic void bc_close(struct rpc_xprt *xprt)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	xprt_disconnect_done(xprt);
26198c2ecf20Sopenharmony_ci}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci/*
26228c2ecf20Sopenharmony_ci * The xprt destroy routine. Again, because this connection is client
26238c2ecf20Sopenharmony_ci * initiated, we do nothing
26248c2ecf20Sopenharmony_ci */
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_cistatic void bc_destroy(struct rpc_xprt *xprt)
26278c2ecf20Sopenharmony_ci{
26288c2ecf20Sopenharmony_ci	dprintk("RPC:       bc_destroy xprt %p\n", xprt);
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
26318c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_cistatic const struct rpc_xprt_ops xs_local_ops = {
26358c2ecf20Sopenharmony_ci	.reserve_xprt		= xprt_reserve_xprt,
26368c2ecf20Sopenharmony_ci	.release_xprt		= xprt_release_xprt,
26378c2ecf20Sopenharmony_ci	.alloc_slot		= xprt_alloc_slot,
26388c2ecf20Sopenharmony_ci	.free_slot		= xprt_free_slot,
26398c2ecf20Sopenharmony_ci	.rpcbind		= xs_local_rpcbind,
26408c2ecf20Sopenharmony_ci	.set_port		= xs_local_set_port,
26418c2ecf20Sopenharmony_ci	.connect		= xs_local_connect,
26428c2ecf20Sopenharmony_ci	.buf_alloc		= rpc_malloc,
26438c2ecf20Sopenharmony_ci	.buf_free		= rpc_free,
26448c2ecf20Sopenharmony_ci	.prepare_request	= xs_stream_prepare_request,
26458c2ecf20Sopenharmony_ci	.send_request		= xs_local_send_request,
26468c2ecf20Sopenharmony_ci	.wait_for_reply_request	= xprt_wait_for_reply_request_def,
26478c2ecf20Sopenharmony_ci	.close			= xs_close,
26488c2ecf20Sopenharmony_ci	.destroy		= xs_destroy,
26498c2ecf20Sopenharmony_ci	.print_stats		= xs_local_print_stats,
26508c2ecf20Sopenharmony_ci	.enable_swap		= xs_enable_swap,
26518c2ecf20Sopenharmony_ci	.disable_swap		= xs_disable_swap,
26528c2ecf20Sopenharmony_ci};
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_cistatic const struct rpc_xprt_ops xs_udp_ops = {
26558c2ecf20Sopenharmony_ci	.set_buffer_size	= xs_udp_set_buffer_size,
26568c2ecf20Sopenharmony_ci	.reserve_xprt		= xprt_reserve_xprt_cong,
26578c2ecf20Sopenharmony_ci	.release_xprt		= xprt_release_xprt_cong,
26588c2ecf20Sopenharmony_ci	.alloc_slot		= xprt_alloc_slot,
26598c2ecf20Sopenharmony_ci	.free_slot		= xprt_free_slot,
26608c2ecf20Sopenharmony_ci	.rpcbind		= rpcb_getport_async,
26618c2ecf20Sopenharmony_ci	.set_port		= xs_set_port,
26628c2ecf20Sopenharmony_ci	.connect		= xs_connect,
26638c2ecf20Sopenharmony_ci	.buf_alloc		= rpc_malloc,
26648c2ecf20Sopenharmony_ci	.buf_free		= rpc_free,
26658c2ecf20Sopenharmony_ci	.send_request		= xs_udp_send_request,
26668c2ecf20Sopenharmony_ci	.wait_for_reply_request	= xprt_wait_for_reply_request_rtt,
26678c2ecf20Sopenharmony_ci	.timer			= xs_udp_timer,
26688c2ecf20Sopenharmony_ci	.release_request	= xprt_release_rqst_cong,
26698c2ecf20Sopenharmony_ci	.close			= xs_close,
26708c2ecf20Sopenharmony_ci	.destroy		= xs_destroy,
26718c2ecf20Sopenharmony_ci	.print_stats		= xs_udp_print_stats,
26728c2ecf20Sopenharmony_ci	.enable_swap		= xs_enable_swap,
26738c2ecf20Sopenharmony_ci	.disable_swap		= xs_disable_swap,
26748c2ecf20Sopenharmony_ci	.inject_disconnect	= xs_inject_disconnect,
26758c2ecf20Sopenharmony_ci};
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_cistatic const struct rpc_xprt_ops xs_tcp_ops = {
26788c2ecf20Sopenharmony_ci	.reserve_xprt		= xprt_reserve_xprt,
26798c2ecf20Sopenharmony_ci	.release_xprt		= xprt_release_xprt,
26808c2ecf20Sopenharmony_ci	.alloc_slot		= xprt_alloc_slot,
26818c2ecf20Sopenharmony_ci	.free_slot		= xprt_free_slot,
26828c2ecf20Sopenharmony_ci	.rpcbind		= rpcb_getport_async,
26838c2ecf20Sopenharmony_ci	.set_port		= xs_set_port,
26848c2ecf20Sopenharmony_ci	.connect		= xs_connect,
26858c2ecf20Sopenharmony_ci	.buf_alloc		= rpc_malloc,
26868c2ecf20Sopenharmony_ci	.buf_free		= rpc_free,
26878c2ecf20Sopenharmony_ci	.prepare_request	= xs_stream_prepare_request,
26888c2ecf20Sopenharmony_ci	.send_request		= xs_tcp_send_request,
26898c2ecf20Sopenharmony_ci	.wait_for_reply_request	= xprt_wait_for_reply_request_def,
26908c2ecf20Sopenharmony_ci	.close			= xs_tcp_shutdown,
26918c2ecf20Sopenharmony_ci	.destroy		= xs_destroy,
26928c2ecf20Sopenharmony_ci	.set_connect_timeout	= xs_tcp_set_connect_timeout,
26938c2ecf20Sopenharmony_ci	.print_stats		= xs_tcp_print_stats,
26948c2ecf20Sopenharmony_ci	.enable_swap		= xs_enable_swap,
26958c2ecf20Sopenharmony_ci	.disable_swap		= xs_disable_swap,
26968c2ecf20Sopenharmony_ci	.inject_disconnect	= xs_inject_disconnect,
26978c2ecf20Sopenharmony_ci#ifdef CONFIG_SUNRPC_BACKCHANNEL
26988c2ecf20Sopenharmony_ci	.bc_setup		= xprt_setup_bc,
26998c2ecf20Sopenharmony_ci	.bc_maxpayload		= xs_tcp_bc_maxpayload,
27008c2ecf20Sopenharmony_ci	.bc_num_slots		= xprt_bc_max_slots,
27018c2ecf20Sopenharmony_ci	.bc_free_rqst		= xprt_free_bc_rqst,
27028c2ecf20Sopenharmony_ci	.bc_destroy		= xprt_destroy_bc,
27038c2ecf20Sopenharmony_ci#endif
27048c2ecf20Sopenharmony_ci};
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci/*
27078c2ecf20Sopenharmony_ci * The rpc_xprt_ops for the server backchannel
27088c2ecf20Sopenharmony_ci */
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_cistatic const struct rpc_xprt_ops bc_tcp_ops = {
27118c2ecf20Sopenharmony_ci	.reserve_xprt		= xprt_reserve_xprt,
27128c2ecf20Sopenharmony_ci	.release_xprt		= xprt_release_xprt,
27138c2ecf20Sopenharmony_ci	.alloc_slot		= xprt_alloc_slot,
27148c2ecf20Sopenharmony_ci	.free_slot		= xprt_free_slot,
27158c2ecf20Sopenharmony_ci	.buf_alloc		= bc_malloc,
27168c2ecf20Sopenharmony_ci	.buf_free		= bc_free,
27178c2ecf20Sopenharmony_ci	.send_request		= bc_send_request,
27188c2ecf20Sopenharmony_ci	.wait_for_reply_request	= xprt_wait_for_reply_request_def,
27198c2ecf20Sopenharmony_ci	.close			= bc_close,
27208c2ecf20Sopenharmony_ci	.destroy		= bc_destroy,
27218c2ecf20Sopenharmony_ci	.print_stats		= xs_tcp_print_stats,
27228c2ecf20Sopenharmony_ci	.enable_swap		= xs_enable_swap,
27238c2ecf20Sopenharmony_ci	.disable_swap		= xs_disable_swap,
27248c2ecf20Sopenharmony_ci	.inject_disconnect	= xs_inject_disconnect,
27258c2ecf20Sopenharmony_ci};
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_cistatic int xs_init_anyaddr(const int family, struct sockaddr *sap)
27288c2ecf20Sopenharmony_ci{
27298c2ecf20Sopenharmony_ci	static const struct sockaddr_in sin = {
27308c2ecf20Sopenharmony_ci		.sin_family		= AF_INET,
27318c2ecf20Sopenharmony_ci		.sin_addr.s_addr	= htonl(INADDR_ANY),
27328c2ecf20Sopenharmony_ci	};
27338c2ecf20Sopenharmony_ci	static const struct sockaddr_in6 sin6 = {
27348c2ecf20Sopenharmony_ci		.sin6_family		= AF_INET6,
27358c2ecf20Sopenharmony_ci		.sin6_addr		= IN6ADDR_ANY_INIT,
27368c2ecf20Sopenharmony_ci	};
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	switch (family) {
27398c2ecf20Sopenharmony_ci	case AF_LOCAL:
27408c2ecf20Sopenharmony_ci		break;
27418c2ecf20Sopenharmony_ci	case AF_INET:
27428c2ecf20Sopenharmony_ci		memcpy(sap, &sin, sizeof(sin));
27438c2ecf20Sopenharmony_ci		break;
27448c2ecf20Sopenharmony_ci	case AF_INET6:
27458c2ecf20Sopenharmony_ci		memcpy(sap, &sin6, sizeof(sin6));
27468c2ecf20Sopenharmony_ci		break;
27478c2ecf20Sopenharmony_ci	default:
27488c2ecf20Sopenharmony_ci		dprintk("RPC:       %s: Bad address family\n", __func__);
27498c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
27508c2ecf20Sopenharmony_ci	}
27518c2ecf20Sopenharmony_ci	return 0;
27528c2ecf20Sopenharmony_ci}
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_cistatic struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
27558c2ecf20Sopenharmony_ci				      unsigned int slot_table_size,
27568c2ecf20Sopenharmony_ci				      unsigned int max_slot_table_size)
27578c2ecf20Sopenharmony_ci{
27588c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
27598c2ecf20Sopenharmony_ci	struct sock_xprt *new;
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	if (args->addrlen > sizeof(xprt->addr)) {
27628c2ecf20Sopenharmony_ci		dprintk("RPC:       xs_setup_xprt: address too large\n");
27638c2ecf20Sopenharmony_ci		return ERR_PTR(-EBADF);
27648c2ecf20Sopenharmony_ci	}
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci	xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size,
27678c2ecf20Sopenharmony_ci			max_slot_table_size);
27688c2ecf20Sopenharmony_ci	if (xprt == NULL) {
27698c2ecf20Sopenharmony_ci		dprintk("RPC:       xs_setup_xprt: couldn't allocate "
27708c2ecf20Sopenharmony_ci				"rpc_xprt\n");
27718c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
27728c2ecf20Sopenharmony_ci	}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	new = container_of(xprt, struct sock_xprt, xprt);
27758c2ecf20Sopenharmony_ci	mutex_init(&new->recv_mutex);
27768c2ecf20Sopenharmony_ci	memcpy(&xprt->addr, args->dstaddr, args->addrlen);
27778c2ecf20Sopenharmony_ci	xprt->addrlen = args->addrlen;
27788c2ecf20Sopenharmony_ci	if (args->srcaddr)
27798c2ecf20Sopenharmony_ci		memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
27808c2ecf20Sopenharmony_ci	else {
27818c2ecf20Sopenharmony_ci		int err;
27828c2ecf20Sopenharmony_ci		err = xs_init_anyaddr(args->dstaddr->sa_family,
27838c2ecf20Sopenharmony_ci					(struct sockaddr *)&new->srcaddr);
27848c2ecf20Sopenharmony_ci		if (err != 0) {
27858c2ecf20Sopenharmony_ci			xprt_free(xprt);
27868c2ecf20Sopenharmony_ci			return ERR_PTR(err);
27878c2ecf20Sopenharmony_ci		}
27888c2ecf20Sopenharmony_ci	}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	return xprt;
27918c2ecf20Sopenharmony_ci}
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_cistatic const struct rpc_timeout xs_local_default_timeout = {
27948c2ecf20Sopenharmony_ci	.to_initval = 10 * HZ,
27958c2ecf20Sopenharmony_ci	.to_maxval = 10 * HZ,
27968c2ecf20Sopenharmony_ci	.to_retries = 2,
27978c2ecf20Sopenharmony_ci};
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci/**
28008c2ecf20Sopenharmony_ci * xs_setup_local - Set up transport to use an AF_LOCAL socket
28018c2ecf20Sopenharmony_ci * @args: rpc transport creation arguments
28028c2ecf20Sopenharmony_ci *
28038c2ecf20Sopenharmony_ci * AF_LOCAL is a "tpi_cots_ord" transport, just like TCP
28048c2ecf20Sopenharmony_ci */
28058c2ecf20Sopenharmony_cistatic struct rpc_xprt *xs_setup_local(struct xprt_create *args)
28068c2ecf20Sopenharmony_ci{
28078c2ecf20Sopenharmony_ci	struct sockaddr_un *sun = (struct sockaddr_un *)args->dstaddr;
28088c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
28098c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
28108c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
28138c2ecf20Sopenharmony_ci			xprt_max_tcp_slot_table_entries);
28148c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
28158c2ecf20Sopenharmony_ci		return xprt;
28168c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	xprt->prot = 0;
28198c2ecf20Sopenharmony_ci	xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	xprt->bind_timeout = XS_BIND_TO;
28228c2ecf20Sopenharmony_ci	xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
28238c2ecf20Sopenharmony_ci	xprt->idle_timeout = XS_IDLE_DISC_TO;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	xprt->ops = &xs_local_ops;
28268c2ecf20Sopenharmony_ci	xprt->timeout = &xs_local_default_timeout;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn);
28298c2ecf20Sopenharmony_ci	INIT_WORK(&transport->error_worker, xs_error_handle);
28308c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&transport->connect_worker, xs_dummy_setup_socket);
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	switch (sun->sun_family) {
28338c2ecf20Sopenharmony_ci	case AF_LOCAL:
28348c2ecf20Sopenharmony_ci		if (sun->sun_path[0] != '/') {
28358c2ecf20Sopenharmony_ci			dprintk("RPC:       bad AF_LOCAL address: %s\n",
28368c2ecf20Sopenharmony_ci					sun->sun_path);
28378c2ecf20Sopenharmony_ci			ret = ERR_PTR(-EINVAL);
28388c2ecf20Sopenharmony_ci			goto out_err;
28398c2ecf20Sopenharmony_ci		}
28408c2ecf20Sopenharmony_ci		xprt_set_bound(xprt);
28418c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL);
28428c2ecf20Sopenharmony_ci		break;
28438c2ecf20Sopenharmony_ci	default:
28448c2ecf20Sopenharmony_ci		ret = ERR_PTR(-EAFNOSUPPORT);
28458c2ecf20Sopenharmony_ci		goto out_err;
28468c2ecf20Sopenharmony_ci	}
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	dprintk("RPC:       set up xprt to %s via AF_LOCAL\n",
28498c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_ADDR]);
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	if (try_module_get(THIS_MODULE))
28528c2ecf20Sopenharmony_ci		return xprt;
28538c2ecf20Sopenharmony_ci	ret = ERR_PTR(-EINVAL);
28548c2ecf20Sopenharmony_ciout_err:
28558c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
28568c2ecf20Sopenharmony_ci	return ret;
28578c2ecf20Sopenharmony_ci}
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic const struct rpc_timeout xs_udp_default_timeout = {
28608c2ecf20Sopenharmony_ci	.to_initval = 5 * HZ,
28618c2ecf20Sopenharmony_ci	.to_maxval = 30 * HZ,
28628c2ecf20Sopenharmony_ci	.to_increment = 5 * HZ,
28638c2ecf20Sopenharmony_ci	.to_retries = 5,
28648c2ecf20Sopenharmony_ci};
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci/**
28678c2ecf20Sopenharmony_ci * xs_setup_udp - Set up transport to use a UDP socket
28688c2ecf20Sopenharmony_ci * @args: rpc transport creation arguments
28698c2ecf20Sopenharmony_ci *
28708c2ecf20Sopenharmony_ci */
28718c2ecf20Sopenharmony_cistatic struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
28728c2ecf20Sopenharmony_ci{
28738c2ecf20Sopenharmony_ci	struct sockaddr *addr = args->dstaddr;
28748c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
28758c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
28768c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries,
28798c2ecf20Sopenharmony_ci			xprt_udp_slot_table_entries);
28808c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
28818c2ecf20Sopenharmony_ci		return xprt;
28828c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	xprt->prot = IPPROTO_UDP;
28858c2ecf20Sopenharmony_ci	/* XXX: header size can vary due to auth type, IPv6, etc. */
28868c2ecf20Sopenharmony_ci	xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	xprt->bind_timeout = XS_BIND_TO;
28898c2ecf20Sopenharmony_ci	xprt->reestablish_timeout = XS_UDP_REEST_TO;
28908c2ecf20Sopenharmony_ci	xprt->idle_timeout = XS_IDLE_DISC_TO;
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	xprt->ops = &xs_udp_ops;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	xprt->timeout = &xs_udp_default_timeout;
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_ci	INIT_WORK(&transport->recv_worker, xs_udp_data_receive_workfn);
28978c2ecf20Sopenharmony_ci	INIT_WORK(&transport->error_worker, xs_error_handle);
28988c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_setup_socket);
28998c2ecf20Sopenharmony_ci
29008c2ecf20Sopenharmony_ci	switch (addr->sa_family) {
29018c2ecf20Sopenharmony_ci	case AF_INET:
29028c2ecf20Sopenharmony_ci		if (((struct sockaddr_in *)addr)->sin_port != htons(0))
29038c2ecf20Sopenharmony_ci			xprt_set_bound(xprt);
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
29068c2ecf20Sopenharmony_ci		break;
29078c2ecf20Sopenharmony_ci	case AF_INET6:
29088c2ecf20Sopenharmony_ci		if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
29098c2ecf20Sopenharmony_ci			xprt_set_bound(xprt);
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
29128c2ecf20Sopenharmony_ci		break;
29138c2ecf20Sopenharmony_ci	default:
29148c2ecf20Sopenharmony_ci		ret = ERR_PTR(-EAFNOSUPPORT);
29158c2ecf20Sopenharmony_ci		goto out_err;
29168c2ecf20Sopenharmony_ci	}
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci	if (xprt_bound(xprt))
29198c2ecf20Sopenharmony_ci		dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
29208c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_ADDR],
29218c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PORT],
29228c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PROTO]);
29238c2ecf20Sopenharmony_ci	else
29248c2ecf20Sopenharmony_ci		dprintk("RPC:       set up xprt to %s (autobind) via %s\n",
29258c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_ADDR],
29268c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PROTO]);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	if (try_module_get(THIS_MODULE))
29298c2ecf20Sopenharmony_ci		return xprt;
29308c2ecf20Sopenharmony_ci	ret = ERR_PTR(-EINVAL);
29318c2ecf20Sopenharmony_ciout_err:
29328c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
29338c2ecf20Sopenharmony_ci	return ret;
29348c2ecf20Sopenharmony_ci}
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_cistatic const struct rpc_timeout xs_tcp_default_timeout = {
29378c2ecf20Sopenharmony_ci	.to_initval = 60 * HZ,
29388c2ecf20Sopenharmony_ci	.to_maxval = 60 * HZ,
29398c2ecf20Sopenharmony_ci	.to_retries = 2,
29408c2ecf20Sopenharmony_ci};
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci/**
29438c2ecf20Sopenharmony_ci * xs_setup_tcp - Set up transport to use a TCP socket
29448c2ecf20Sopenharmony_ci * @args: rpc transport creation arguments
29458c2ecf20Sopenharmony_ci *
29468c2ecf20Sopenharmony_ci */
29478c2ecf20Sopenharmony_cistatic struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
29488c2ecf20Sopenharmony_ci{
29498c2ecf20Sopenharmony_ci	struct sockaddr *addr = args->dstaddr;
29508c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
29518c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
29528c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
29538c2ecf20Sopenharmony_ci	unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci	if (args->flags & XPRT_CREATE_INFINITE_SLOTS)
29568c2ecf20Sopenharmony_ci		max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
29598c2ecf20Sopenharmony_ci			max_slot_table_size);
29608c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
29618c2ecf20Sopenharmony_ci		return xprt;
29628c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	xprt->prot = IPPROTO_TCP;
29658c2ecf20Sopenharmony_ci	xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	xprt->bind_timeout = XS_BIND_TO;
29688c2ecf20Sopenharmony_ci	xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
29698c2ecf20Sopenharmony_ci	xprt->idle_timeout = XS_IDLE_DISC_TO;
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	xprt->ops = &xs_tcp_ops;
29728c2ecf20Sopenharmony_ci	xprt->timeout = &xs_tcp_default_timeout;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	xprt->max_reconnect_timeout = xprt->timeout->to_maxval;
29758c2ecf20Sopenharmony_ci	xprt->connect_timeout = xprt->timeout->to_initval *
29768c2ecf20Sopenharmony_ci		(xprt->timeout->to_retries + 1);
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn);
29798c2ecf20Sopenharmony_ci	INIT_WORK(&transport->error_worker, xs_error_handle);
29808c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket);
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	switch (addr->sa_family) {
29838c2ecf20Sopenharmony_ci	case AF_INET:
29848c2ecf20Sopenharmony_ci		if (((struct sockaddr_in *)addr)->sin_port != htons(0))
29858c2ecf20Sopenharmony_ci			xprt_set_bound(xprt);
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
29888c2ecf20Sopenharmony_ci		break;
29898c2ecf20Sopenharmony_ci	case AF_INET6:
29908c2ecf20Sopenharmony_ci		if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
29918c2ecf20Sopenharmony_ci			xprt_set_bound(xprt);
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
29948c2ecf20Sopenharmony_ci		break;
29958c2ecf20Sopenharmony_ci	default:
29968c2ecf20Sopenharmony_ci		ret = ERR_PTR(-EAFNOSUPPORT);
29978c2ecf20Sopenharmony_ci		goto out_err;
29988c2ecf20Sopenharmony_ci	}
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	if (xprt_bound(xprt))
30018c2ecf20Sopenharmony_ci		dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
30028c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_ADDR],
30038c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PORT],
30048c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PROTO]);
30058c2ecf20Sopenharmony_ci	else
30068c2ecf20Sopenharmony_ci		dprintk("RPC:       set up xprt to %s (autobind) via %s\n",
30078c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_ADDR],
30088c2ecf20Sopenharmony_ci				xprt->address_strings[RPC_DISPLAY_PROTO]);
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	if (try_module_get(THIS_MODULE))
30118c2ecf20Sopenharmony_ci		return xprt;
30128c2ecf20Sopenharmony_ci	ret = ERR_PTR(-EINVAL);
30138c2ecf20Sopenharmony_ciout_err:
30148c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
30158c2ecf20Sopenharmony_ci	return ret;
30168c2ecf20Sopenharmony_ci}
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci/**
30198c2ecf20Sopenharmony_ci * xs_setup_bc_tcp - Set up transport to use a TCP backchannel socket
30208c2ecf20Sopenharmony_ci * @args: rpc transport creation arguments
30218c2ecf20Sopenharmony_ci *
30228c2ecf20Sopenharmony_ci */
30238c2ecf20Sopenharmony_cistatic struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
30248c2ecf20Sopenharmony_ci{
30258c2ecf20Sopenharmony_ci	struct sockaddr *addr = args->dstaddr;
30268c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
30278c2ecf20Sopenharmony_ci	struct sock_xprt *transport;
30288c2ecf20Sopenharmony_ci	struct svc_sock *bc_sock;
30298c2ecf20Sopenharmony_ci	struct rpc_xprt *ret;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
30328c2ecf20Sopenharmony_ci			xprt_tcp_slot_table_entries);
30338c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
30348c2ecf20Sopenharmony_ci		return xprt;
30358c2ecf20Sopenharmony_ci	transport = container_of(xprt, struct sock_xprt, xprt);
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	xprt->prot = IPPROTO_TCP;
30388c2ecf20Sopenharmony_ci	xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
30398c2ecf20Sopenharmony_ci	xprt->timeout = &xs_tcp_default_timeout;
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci	/* backchannel */
30428c2ecf20Sopenharmony_ci	xprt_set_bound(xprt);
30438c2ecf20Sopenharmony_ci	xprt->bind_timeout = 0;
30448c2ecf20Sopenharmony_ci	xprt->reestablish_timeout = 0;
30458c2ecf20Sopenharmony_ci	xprt->idle_timeout = 0;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	xprt->ops = &bc_tcp_ops;
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ci	switch (addr->sa_family) {
30508c2ecf20Sopenharmony_ci	case AF_INET:
30518c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "tcp",
30528c2ecf20Sopenharmony_ci					 RPCBIND_NETID_TCP);
30538c2ecf20Sopenharmony_ci		break;
30548c2ecf20Sopenharmony_ci	case AF_INET6:
30558c2ecf20Sopenharmony_ci		xs_format_peer_addresses(xprt, "tcp",
30568c2ecf20Sopenharmony_ci				   RPCBIND_NETID_TCP6);
30578c2ecf20Sopenharmony_ci		break;
30588c2ecf20Sopenharmony_ci	default:
30598c2ecf20Sopenharmony_ci		ret = ERR_PTR(-EAFNOSUPPORT);
30608c2ecf20Sopenharmony_ci		goto out_err;
30618c2ecf20Sopenharmony_ci	}
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	dprintk("RPC:       set up xprt to %s (port %s) via %s\n",
30648c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_ADDR],
30658c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PORT],
30668c2ecf20Sopenharmony_ci			xprt->address_strings[RPC_DISPLAY_PROTO]);
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci	/*
30698c2ecf20Sopenharmony_ci	 * Once we've associated a backchannel xprt with a connection,
30708c2ecf20Sopenharmony_ci	 * we want to keep it around as long as the connection lasts,
30718c2ecf20Sopenharmony_ci	 * in case we need to start using it for a backchannel again;
30728c2ecf20Sopenharmony_ci	 * this reference won't be dropped until bc_xprt is destroyed.
30738c2ecf20Sopenharmony_ci	 */
30748c2ecf20Sopenharmony_ci	xprt_get(xprt);
30758c2ecf20Sopenharmony_ci	args->bc_xprt->xpt_bc_xprt = xprt;
30768c2ecf20Sopenharmony_ci	xprt->bc_xprt = args->bc_xprt;
30778c2ecf20Sopenharmony_ci	bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
30788c2ecf20Sopenharmony_ci	transport->sock = bc_sock->sk_sock;
30798c2ecf20Sopenharmony_ci	transport->inet = bc_sock->sk_sk;
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	/*
30828c2ecf20Sopenharmony_ci	 * Since we don't want connections for the backchannel, we set
30838c2ecf20Sopenharmony_ci	 * the xprt status to connected
30848c2ecf20Sopenharmony_ci	 */
30858c2ecf20Sopenharmony_ci	xprt_set_connected(xprt);
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci	if (try_module_get(THIS_MODULE))
30888c2ecf20Sopenharmony_ci		return xprt;
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	args->bc_xprt->xpt_bc_xprt = NULL;
30918c2ecf20Sopenharmony_ci	args->bc_xprt->xpt_bc_xps = NULL;
30928c2ecf20Sopenharmony_ci	xprt_put(xprt);
30938c2ecf20Sopenharmony_ci	ret = ERR_PTR(-EINVAL);
30948c2ecf20Sopenharmony_ciout_err:
30958c2ecf20Sopenharmony_ci	xs_xprt_free(xprt);
30968c2ecf20Sopenharmony_ci	return ret;
30978c2ecf20Sopenharmony_ci}
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_cistatic struct xprt_class	xs_local_transport = {
31008c2ecf20Sopenharmony_ci	.list		= LIST_HEAD_INIT(xs_local_transport.list),
31018c2ecf20Sopenharmony_ci	.name		= "named UNIX socket",
31028c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
31038c2ecf20Sopenharmony_ci	.ident		= XPRT_TRANSPORT_LOCAL,
31048c2ecf20Sopenharmony_ci	.setup		= xs_setup_local,
31058c2ecf20Sopenharmony_ci	.netid		= { "" },
31068c2ecf20Sopenharmony_ci};
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_cistatic struct xprt_class	xs_udp_transport = {
31098c2ecf20Sopenharmony_ci	.list		= LIST_HEAD_INIT(xs_udp_transport.list),
31108c2ecf20Sopenharmony_ci	.name		= "udp",
31118c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
31128c2ecf20Sopenharmony_ci	.ident		= XPRT_TRANSPORT_UDP,
31138c2ecf20Sopenharmony_ci	.setup		= xs_setup_udp,
31148c2ecf20Sopenharmony_ci	.netid		= { "udp", "udp6", "" },
31158c2ecf20Sopenharmony_ci};
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_cistatic struct xprt_class	xs_tcp_transport = {
31188c2ecf20Sopenharmony_ci	.list		= LIST_HEAD_INIT(xs_tcp_transport.list),
31198c2ecf20Sopenharmony_ci	.name		= "tcp",
31208c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
31218c2ecf20Sopenharmony_ci	.ident		= XPRT_TRANSPORT_TCP,
31228c2ecf20Sopenharmony_ci	.setup		= xs_setup_tcp,
31238c2ecf20Sopenharmony_ci	.netid		= { "tcp", "tcp6", "" },
31248c2ecf20Sopenharmony_ci};
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_cistatic struct xprt_class	xs_bc_tcp_transport = {
31278c2ecf20Sopenharmony_ci	.list		= LIST_HEAD_INIT(xs_bc_tcp_transport.list),
31288c2ecf20Sopenharmony_ci	.name		= "tcp NFSv4.1 backchannel",
31298c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
31308c2ecf20Sopenharmony_ci	.ident		= XPRT_TRANSPORT_BC_TCP,
31318c2ecf20Sopenharmony_ci	.setup		= xs_setup_bc_tcp,
31328c2ecf20Sopenharmony_ci	.netid		= { "" },
31338c2ecf20Sopenharmony_ci};
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ci/**
31368c2ecf20Sopenharmony_ci * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
31378c2ecf20Sopenharmony_ci *
31388c2ecf20Sopenharmony_ci */
31398c2ecf20Sopenharmony_ciint init_socket_xprt(void)
31408c2ecf20Sopenharmony_ci{
31418c2ecf20Sopenharmony_ci	if (!sunrpc_table_header)
31428c2ecf20Sopenharmony_ci		sunrpc_table_header = register_sysctl_table(sunrpc_table);
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_ci	xprt_register_transport(&xs_local_transport);
31458c2ecf20Sopenharmony_ci	xprt_register_transport(&xs_udp_transport);
31468c2ecf20Sopenharmony_ci	xprt_register_transport(&xs_tcp_transport);
31478c2ecf20Sopenharmony_ci	xprt_register_transport(&xs_bc_tcp_transport);
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	return 0;
31508c2ecf20Sopenharmony_ci}
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci/**
31538c2ecf20Sopenharmony_ci * cleanup_socket_xprt - remove xprtsock's sysctls, unregister
31548c2ecf20Sopenharmony_ci *
31558c2ecf20Sopenharmony_ci */
31568c2ecf20Sopenharmony_civoid cleanup_socket_xprt(void)
31578c2ecf20Sopenharmony_ci{
31588c2ecf20Sopenharmony_ci	if (sunrpc_table_header) {
31598c2ecf20Sopenharmony_ci		unregister_sysctl_table(sunrpc_table_header);
31608c2ecf20Sopenharmony_ci		sunrpc_table_header = NULL;
31618c2ecf20Sopenharmony_ci	}
31628c2ecf20Sopenharmony_ci
31638c2ecf20Sopenharmony_ci	xprt_unregister_transport(&xs_local_transport);
31648c2ecf20Sopenharmony_ci	xprt_unregister_transport(&xs_udp_transport);
31658c2ecf20Sopenharmony_ci	xprt_unregister_transport(&xs_tcp_transport);
31668c2ecf20Sopenharmony_ci	xprt_unregister_transport(&xs_bc_tcp_transport);
31678c2ecf20Sopenharmony_ci}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_cistatic int param_set_uint_minmax(const char *val,
31708c2ecf20Sopenharmony_ci		const struct kernel_param *kp,
31718c2ecf20Sopenharmony_ci		unsigned int min, unsigned int max)
31728c2ecf20Sopenharmony_ci{
31738c2ecf20Sopenharmony_ci	unsigned int num;
31748c2ecf20Sopenharmony_ci	int ret;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	if (!val)
31778c2ecf20Sopenharmony_ci		return -EINVAL;
31788c2ecf20Sopenharmony_ci	ret = kstrtouint(val, 0, &num);
31798c2ecf20Sopenharmony_ci	if (ret)
31808c2ecf20Sopenharmony_ci		return ret;
31818c2ecf20Sopenharmony_ci	if (num < min || num > max)
31828c2ecf20Sopenharmony_ci		return -EINVAL;
31838c2ecf20Sopenharmony_ci	*((unsigned int *)kp->arg) = num;
31848c2ecf20Sopenharmony_ci	return 0;
31858c2ecf20Sopenharmony_ci}
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_cistatic int param_set_portnr(const char *val, const struct kernel_param *kp)
31888c2ecf20Sopenharmony_ci{
31898c2ecf20Sopenharmony_ci	return param_set_uint_minmax(val, kp,
31908c2ecf20Sopenharmony_ci			RPC_MIN_RESVPORT,
31918c2ecf20Sopenharmony_ci			RPC_MAX_RESVPORT);
31928c2ecf20Sopenharmony_ci}
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_portnr = {
31958c2ecf20Sopenharmony_ci	.set = param_set_portnr,
31968c2ecf20Sopenharmony_ci	.get = param_get_uint,
31978c2ecf20Sopenharmony_ci};
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci#define param_check_portnr(name, p) \
32008c2ecf20Sopenharmony_ci	__param_check(name, p, unsigned int);
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_cimodule_param_named(min_resvport, xprt_min_resvport, portnr, 0644);
32038c2ecf20Sopenharmony_cimodule_param_named(max_resvport, xprt_max_resvport, portnr, 0644);
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_cistatic int param_set_slot_table_size(const char *val,
32068c2ecf20Sopenharmony_ci				     const struct kernel_param *kp)
32078c2ecf20Sopenharmony_ci{
32088c2ecf20Sopenharmony_ci	return param_set_uint_minmax(val, kp,
32098c2ecf20Sopenharmony_ci			RPC_MIN_SLOT_TABLE,
32108c2ecf20Sopenharmony_ci			RPC_MAX_SLOT_TABLE);
32118c2ecf20Sopenharmony_ci}
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_slot_table_size = {
32148c2ecf20Sopenharmony_ci	.set = param_set_slot_table_size,
32158c2ecf20Sopenharmony_ci	.get = param_get_uint,
32168c2ecf20Sopenharmony_ci};
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci#define param_check_slot_table_size(name, p) \
32198c2ecf20Sopenharmony_ci	__param_check(name, p, unsigned int);
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_cistatic int param_set_max_slot_table_size(const char *val,
32228c2ecf20Sopenharmony_ci				     const struct kernel_param *kp)
32238c2ecf20Sopenharmony_ci{
32248c2ecf20Sopenharmony_ci	return param_set_uint_minmax(val, kp,
32258c2ecf20Sopenharmony_ci			RPC_MIN_SLOT_TABLE,
32268c2ecf20Sopenharmony_ci			RPC_MAX_SLOT_TABLE_LIMIT);
32278c2ecf20Sopenharmony_ci}
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_max_slot_table_size = {
32308c2ecf20Sopenharmony_ci	.set = param_set_max_slot_table_size,
32318c2ecf20Sopenharmony_ci	.get = param_get_uint,
32328c2ecf20Sopenharmony_ci};
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_ci#define param_check_max_slot_table_size(name, p) \
32358c2ecf20Sopenharmony_ci	__param_check(name, p, unsigned int);
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_cimodule_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries,
32388c2ecf20Sopenharmony_ci		   slot_table_size, 0644);
32398c2ecf20Sopenharmony_cimodule_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries,
32408c2ecf20Sopenharmony_ci		   max_slot_table_size, 0644);
32418c2ecf20Sopenharmony_cimodule_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries,
32428c2ecf20Sopenharmony_ci		   slot_table_size, 0644);
3243