162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/net/sunrpc/svc_xprt.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Tom Tucker <tom@opengridcomputing.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/sched.h>
962306a36Sopenharmony_ci#include <linux/sched/mm.h>
1062306a36Sopenharmony_ci#include <linux/errno.h>
1162306a36Sopenharmony_ci#include <linux/freezer.h>
1262306a36Sopenharmony_ci#include <linux/kthread.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <net/sock.h>
1562306a36Sopenharmony_ci#include <linux/sunrpc/addr.h>
1662306a36Sopenharmony_ci#include <linux/sunrpc/stats.h>
1762306a36Sopenharmony_ci#include <linux/sunrpc/svc_xprt.h>
1862306a36Sopenharmony_ci#include <linux/sunrpc/svcsock.h>
1962306a36Sopenharmony_ci#include <linux/sunrpc/xprt.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/netdevice.h>
2262306a36Sopenharmony_ci#include <trace/events/sunrpc.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic unsigned int svc_rpc_per_connection_limit __read_mostly;
2762306a36Sopenharmony_cimodule_param(svc_rpc_per_connection_limit, uint, 0644);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
3162306a36Sopenharmony_cistatic int svc_deferred_recv(struct svc_rqst *rqstp);
3262306a36Sopenharmony_cistatic struct cache_deferred_req *svc_defer(struct cache_req *req);
3362306a36Sopenharmony_cistatic void svc_age_temp_xprts(struct timer_list *t);
3462306a36Sopenharmony_cistatic void svc_delete_xprt(struct svc_xprt *xprt);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* apparently the "standard" is that clients close
3762306a36Sopenharmony_ci * idle connections after 5 minutes, servers after
3862306a36Sopenharmony_ci * 6 minutes
3962306a36Sopenharmony_ci *   http://nfsv4bat.org/Documents/ConnectAThon/1996/nfstcp.pdf
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistatic int svc_conn_age_period = 6*60;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* List of registered transport classes */
4462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(svc_xprt_class_lock);
4562306a36Sopenharmony_cistatic LIST_HEAD(svc_xprt_class_list);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* SMP locking strategy:
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci *	svc_pool->sp_lock protects most of the fields of that pool.
5062306a36Sopenharmony_ci *	svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
5162306a36Sopenharmony_ci *	when both need to be taken (rare), svc_serv->sv_lock is first.
5262306a36Sopenharmony_ci *	The "service mutex" protects svc_serv->sv_nrthread.
5362306a36Sopenharmony_ci *	svc_sock->sk_lock protects the svc_sock->sk_deferred list
5462306a36Sopenharmony_ci *             and the ->sk_info_authunix cache.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *	The XPT_BUSY bit in xprt->xpt_flags prevents a transport being
5762306a36Sopenharmony_ci *	enqueued multiply. During normal transport processing this bit
5862306a36Sopenharmony_ci *	is set by svc_xprt_enqueue and cleared by svc_xprt_received.
5962306a36Sopenharmony_ci *	Providers should not manipulate this bit directly.
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci *	Some flags can be set to certain values at any time
6262306a36Sopenharmony_ci *	providing that certain rules are followed:
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci *	XPT_CONN, XPT_DATA:
6562306a36Sopenharmony_ci *		- Can be set or cleared at any time.
6662306a36Sopenharmony_ci *		- After a set, svc_xprt_enqueue must be called to enqueue
6762306a36Sopenharmony_ci *		  the transport for processing.
6862306a36Sopenharmony_ci *		- After a clear, the transport must be read/accepted.
6962306a36Sopenharmony_ci *		  If this succeeds, it must be set again.
7062306a36Sopenharmony_ci *	XPT_CLOSE:
7162306a36Sopenharmony_ci *		- Can set at any time. It is never cleared.
7262306a36Sopenharmony_ci *      XPT_DEAD:
7362306a36Sopenharmony_ci *		- Can only be set while XPT_BUSY is held which ensures
7462306a36Sopenharmony_ci *		  that no other thread will be using the transport or will
7562306a36Sopenharmony_ci *		  try to set XPT_DEAD.
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * svc_reg_xprt_class - Register a server-side RPC transport class
8062306a36Sopenharmony_ci * @xcl: New transport class to be registered
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Returns zero on success; otherwise a negative errno is returned.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_ciint svc_reg_xprt_class(struct svc_xprt_class *xcl)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct svc_xprt_class *cl;
8762306a36Sopenharmony_ci	int res = -EEXIST;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	INIT_LIST_HEAD(&xcl->xcl_list);
9062306a36Sopenharmony_ci	spin_lock(&svc_xprt_class_lock);
9162306a36Sopenharmony_ci	/* Make sure there isn't already a class with the same name */
9262306a36Sopenharmony_ci	list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
9362306a36Sopenharmony_ci		if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
9462306a36Sopenharmony_ci			goto out;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci	list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
9762306a36Sopenharmony_ci	res = 0;
9862306a36Sopenharmony_ciout:
9962306a36Sopenharmony_ci	spin_unlock(&svc_xprt_class_lock);
10062306a36Sopenharmony_ci	return res;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_reg_xprt_class);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci * svc_unreg_xprt_class - Unregister a server-side RPC transport class
10662306a36Sopenharmony_ci * @xcl: Transport class to be unregistered
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci */
10962306a36Sopenharmony_civoid svc_unreg_xprt_class(struct svc_xprt_class *xcl)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	spin_lock(&svc_xprt_class_lock);
11262306a36Sopenharmony_ci	list_del_init(&xcl->xcl_list);
11362306a36Sopenharmony_ci	spin_unlock(&svc_xprt_class_lock);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/**
11862306a36Sopenharmony_ci * svc_print_xprts - Format the transport list for printing
11962306a36Sopenharmony_ci * @buf: target buffer for formatted address
12062306a36Sopenharmony_ci * @maxlen: length of target buffer
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * Fills in @buf with a string containing a list of transport names, each name
12362306a36Sopenharmony_ci * terminated with '\n'. If the buffer is too small, some entries may be
12462306a36Sopenharmony_ci * missing, but it is guaranteed that all lines in the output buffer are
12562306a36Sopenharmony_ci * complete.
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * Returns positive length of the filled-in string.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ciint svc_print_xprts(char *buf, int maxlen)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct svc_xprt_class *xcl;
13262306a36Sopenharmony_ci	char tmpstr[80];
13362306a36Sopenharmony_ci	int len = 0;
13462306a36Sopenharmony_ci	buf[0] = '\0';
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	spin_lock(&svc_xprt_class_lock);
13762306a36Sopenharmony_ci	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
13862306a36Sopenharmony_ci		int slen;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		slen = snprintf(tmpstr, sizeof(tmpstr), "%s %d\n",
14162306a36Sopenharmony_ci				xcl->xcl_name, xcl->xcl_max_payload);
14262306a36Sopenharmony_ci		if (slen >= sizeof(tmpstr) || len + slen >= maxlen)
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci		len += slen;
14562306a36Sopenharmony_ci		strcat(buf, tmpstr);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	spin_unlock(&svc_xprt_class_lock);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return len;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/**
15362306a36Sopenharmony_ci * svc_xprt_deferred_close - Close a transport
15462306a36Sopenharmony_ci * @xprt: transport instance
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * Used in contexts that need to defer the work of shutting down
15762306a36Sopenharmony_ci * the transport to an nfsd thread.
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_civoid svc_xprt_deferred_close(struct svc_xprt *xprt)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	if (!test_and_set_bit(XPT_CLOSE, &xprt->xpt_flags))
16262306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_deferred_close);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void svc_xprt_free(struct kref *kref)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct svc_xprt *xprt =
16962306a36Sopenharmony_ci		container_of(kref, struct svc_xprt, xpt_ref);
17062306a36Sopenharmony_ci	struct module *owner = xprt->xpt_class->xcl_owner;
17162306a36Sopenharmony_ci	if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
17262306a36Sopenharmony_ci		svcauth_unix_info_release(xprt);
17362306a36Sopenharmony_ci	put_cred(xprt->xpt_cred);
17462306a36Sopenharmony_ci	put_net_track(xprt->xpt_net, &xprt->ns_tracker);
17562306a36Sopenharmony_ci	/* See comment on corresponding get in xs_setup_bc_tcp(): */
17662306a36Sopenharmony_ci	if (xprt->xpt_bc_xprt)
17762306a36Sopenharmony_ci		xprt_put(xprt->xpt_bc_xprt);
17862306a36Sopenharmony_ci	if (xprt->xpt_bc_xps)
17962306a36Sopenharmony_ci		xprt_switch_put(xprt->xpt_bc_xps);
18062306a36Sopenharmony_ci	trace_svc_xprt_free(xprt);
18162306a36Sopenharmony_ci	xprt->xpt_ops->xpo_free(xprt);
18262306a36Sopenharmony_ci	module_put(owner);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_civoid svc_xprt_put(struct svc_xprt *xprt)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	kref_put(&xprt->xpt_ref, svc_xprt_free);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_put);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/*
19262306a36Sopenharmony_ci * Called by transport drivers to initialize the transport independent
19362306a36Sopenharmony_ci * portion of the transport instance.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_civoid svc_xprt_init(struct net *net, struct svc_xprt_class *xcl,
19662306a36Sopenharmony_ci		   struct svc_xprt *xprt, struct svc_serv *serv)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	memset(xprt, 0, sizeof(*xprt));
19962306a36Sopenharmony_ci	xprt->xpt_class = xcl;
20062306a36Sopenharmony_ci	xprt->xpt_ops = xcl->xcl_ops;
20162306a36Sopenharmony_ci	kref_init(&xprt->xpt_ref);
20262306a36Sopenharmony_ci	xprt->xpt_server = serv;
20362306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xpt_list);
20462306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xpt_ready);
20562306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xpt_deferred);
20662306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xpt_users);
20762306a36Sopenharmony_ci	mutex_init(&xprt->xpt_mutex);
20862306a36Sopenharmony_ci	spin_lock_init(&xprt->xpt_lock);
20962306a36Sopenharmony_ci	set_bit(XPT_BUSY, &xprt->xpt_flags);
21062306a36Sopenharmony_ci	xprt->xpt_net = get_net_track(net, &xprt->ns_tracker, GFP_ATOMIC);
21162306a36Sopenharmony_ci	strcpy(xprt->xpt_remotebuf, "uninitialized");
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_init);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
21662306a36Sopenharmony_ci					 struct svc_serv *serv,
21762306a36Sopenharmony_ci					 struct net *net,
21862306a36Sopenharmony_ci					 const int family,
21962306a36Sopenharmony_ci					 const unsigned short port,
22062306a36Sopenharmony_ci					 int flags)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct sockaddr_in sin = {
22362306a36Sopenharmony_ci		.sin_family		= AF_INET,
22462306a36Sopenharmony_ci		.sin_addr.s_addr	= htonl(INADDR_ANY),
22562306a36Sopenharmony_ci		.sin_port		= htons(port),
22662306a36Sopenharmony_ci	};
22762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
22862306a36Sopenharmony_ci	struct sockaddr_in6 sin6 = {
22962306a36Sopenharmony_ci		.sin6_family		= AF_INET6,
23062306a36Sopenharmony_ci		.sin6_addr		= IN6ADDR_ANY_INIT,
23162306a36Sopenharmony_ci		.sin6_port		= htons(port),
23262306a36Sopenharmony_ci	};
23362306a36Sopenharmony_ci#endif
23462306a36Sopenharmony_ci	struct svc_xprt *xprt;
23562306a36Sopenharmony_ci	struct sockaddr *sap;
23662306a36Sopenharmony_ci	size_t len;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	switch (family) {
23962306a36Sopenharmony_ci	case PF_INET:
24062306a36Sopenharmony_ci		sap = (struct sockaddr *)&sin;
24162306a36Sopenharmony_ci		len = sizeof(sin);
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
24462306a36Sopenharmony_ci	case PF_INET6:
24562306a36Sopenharmony_ci		sap = (struct sockaddr *)&sin6;
24662306a36Sopenharmony_ci		len = sizeof(sin6);
24762306a36Sopenharmony_ci		break;
24862306a36Sopenharmony_ci#endif
24962306a36Sopenharmony_ci	default:
25062306a36Sopenharmony_ci		return ERR_PTR(-EAFNOSUPPORT);
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	xprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
25462306a36Sopenharmony_ci	if (IS_ERR(xprt))
25562306a36Sopenharmony_ci		trace_svc_xprt_create_err(serv->sv_program->pg_name,
25662306a36Sopenharmony_ci					  xcl->xcl_name, sap, len, xprt);
25762306a36Sopenharmony_ci	return xprt;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/**
26162306a36Sopenharmony_ci * svc_xprt_received - start next receiver thread
26262306a36Sopenharmony_ci * @xprt: controlling transport
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * The caller must hold the XPT_BUSY bit and must
26562306a36Sopenharmony_ci * not thereafter touch transport data.
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * Note: XPT_DATA only gets cleared when a read-attempt finds no (or
26862306a36Sopenharmony_ci * insufficient) data.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_civoid svc_xprt_received(struct svc_xprt *xprt)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) {
27362306a36Sopenharmony_ci		WARN_ONCE(1, "xprt=0x%p already busy!", xprt);
27462306a36Sopenharmony_ci		return;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* As soon as we clear busy, the xprt could be closed and
27862306a36Sopenharmony_ci	 * 'put', so we need a reference to call svc_xprt_enqueue with:
27962306a36Sopenharmony_ci	 */
28062306a36Sopenharmony_ci	svc_xprt_get(xprt);
28162306a36Sopenharmony_ci	smp_mb__before_atomic();
28262306a36Sopenharmony_ci	clear_bit(XPT_BUSY, &xprt->xpt_flags);
28362306a36Sopenharmony_ci	svc_xprt_enqueue(xprt);
28462306a36Sopenharmony_ci	svc_xprt_put(xprt);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_received);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_civoid svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	clear_bit(XPT_TEMP, &new->xpt_flags);
29162306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
29262306a36Sopenharmony_ci	list_add(&new->xpt_list, &serv->sv_permsocks);
29362306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
29462306a36Sopenharmony_ci	svc_xprt_received(new);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
29862306a36Sopenharmony_ci			    struct net *net, const int family,
29962306a36Sopenharmony_ci			    const unsigned short port, int flags,
30062306a36Sopenharmony_ci			    const struct cred *cred)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct svc_xprt_class *xcl;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	spin_lock(&svc_xprt_class_lock);
30562306a36Sopenharmony_ci	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
30662306a36Sopenharmony_ci		struct svc_xprt *newxprt;
30762306a36Sopenharmony_ci		unsigned short newport;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		if (strcmp(xprt_name, xcl->xcl_name))
31062306a36Sopenharmony_ci			continue;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		if (!try_module_get(xcl->xcl_owner))
31362306a36Sopenharmony_ci			goto err;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		spin_unlock(&svc_xprt_class_lock);
31662306a36Sopenharmony_ci		newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
31762306a36Sopenharmony_ci		if (IS_ERR(newxprt)) {
31862306a36Sopenharmony_ci			module_put(xcl->xcl_owner);
31962306a36Sopenharmony_ci			return PTR_ERR(newxprt);
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci		newxprt->xpt_cred = get_cred(cred);
32262306a36Sopenharmony_ci		svc_add_new_perm_xprt(serv, newxprt);
32362306a36Sopenharmony_ci		newport = svc_xprt_local_port(newxprt);
32462306a36Sopenharmony_ci		return newport;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci err:
32762306a36Sopenharmony_ci	spin_unlock(&svc_xprt_class_lock);
32862306a36Sopenharmony_ci	/* This errno is exposed to user space.  Provide a reasonable
32962306a36Sopenharmony_ci	 * perror msg for a bad transport. */
33062306a36Sopenharmony_ci	return -EPROTONOSUPPORT;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/**
33462306a36Sopenharmony_ci * svc_xprt_create - Add a new listener to @serv
33562306a36Sopenharmony_ci * @serv: target RPC service
33662306a36Sopenharmony_ci * @xprt_name: transport class name
33762306a36Sopenharmony_ci * @net: network namespace
33862306a36Sopenharmony_ci * @family: network address family
33962306a36Sopenharmony_ci * @port: listener port
34062306a36Sopenharmony_ci * @flags: SVC_SOCK flags
34162306a36Sopenharmony_ci * @cred: credential to bind to this transport
34262306a36Sopenharmony_ci *
34362306a36Sopenharmony_ci * Return values:
34462306a36Sopenharmony_ci *   %0: New listener added successfully
34562306a36Sopenharmony_ci *   %-EPROTONOSUPPORT: Requested transport type not supported
34662306a36Sopenharmony_ci */
34762306a36Sopenharmony_ciint svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
34862306a36Sopenharmony_ci		    struct net *net, const int family,
34962306a36Sopenharmony_ci		    const unsigned short port, int flags,
35062306a36Sopenharmony_ci		    const struct cred *cred)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	int err;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred);
35562306a36Sopenharmony_ci	if (err == -EPROTONOSUPPORT) {
35662306a36Sopenharmony_ci		request_module("svc%s", xprt_name);
35762306a36Sopenharmony_ci		err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	return err;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_create);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/*
36462306a36Sopenharmony_ci * Copy the local and remote xprt addresses to the rqstp structure
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_civoid svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
36962306a36Sopenharmony_ci	rqstp->rq_addrlen = xprt->xpt_remotelen;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * Destination address in request is needed for binding the
37362306a36Sopenharmony_ci	 * source address in RPC replies/callbacks later.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	memcpy(&rqstp->rq_daddr, &xprt->xpt_local, xprt->xpt_locallen);
37662306a36Sopenharmony_ci	rqstp->rq_daddrlen = xprt->xpt_locallen;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/**
38162306a36Sopenharmony_ci * svc_print_addr - Format rq_addr field for printing
38262306a36Sopenharmony_ci * @rqstp: svc_rqst struct containing address to print
38362306a36Sopenharmony_ci * @buf: target buffer for formatted address
38462306a36Sopenharmony_ci * @len: length of target buffer
38562306a36Sopenharmony_ci *
38662306a36Sopenharmony_ci */
38762306a36Sopenharmony_cichar *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	return __svc_print_addr(svc_addr(rqstp), buf, len);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_print_addr);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic bool svc_xprt_slots_in_range(struct svc_xprt *xprt)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	unsigned int limit = svc_rpc_per_connection_limit;
39662306a36Sopenharmony_ci	int nrqsts = atomic_read(&xprt->xpt_nr_rqsts);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return limit == 0 || (nrqsts >= 0 && nrqsts < limit);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic bool svc_xprt_reserve_slot(struct svc_rqst *rqstp, struct svc_xprt *xprt)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	if (!test_bit(RQ_DATA, &rqstp->rq_flags)) {
40462306a36Sopenharmony_ci		if (!svc_xprt_slots_in_range(xprt))
40562306a36Sopenharmony_ci			return false;
40662306a36Sopenharmony_ci		atomic_inc(&xprt->xpt_nr_rqsts);
40762306a36Sopenharmony_ci		set_bit(RQ_DATA, &rqstp->rq_flags);
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	return true;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic void svc_xprt_release_slot(struct svc_rqst *rqstp)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct svc_xprt	*xprt = rqstp->rq_xprt;
41562306a36Sopenharmony_ci	if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) {
41662306a36Sopenharmony_ci		atomic_dec(&xprt->xpt_nr_rqsts);
41762306a36Sopenharmony_ci		smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
41862306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic bool svc_xprt_ready(struct svc_xprt *xprt)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	unsigned long xpt_flags;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/*
42762306a36Sopenharmony_ci	 * If another cpu has recently updated xpt_flags,
42862306a36Sopenharmony_ci	 * sk_sock->flags, xpt_reserved, or xpt_nr_rqsts, we need to
42962306a36Sopenharmony_ci	 * know about it; otherwise it's possible that both that cpu and
43062306a36Sopenharmony_ci	 * this one could call svc_xprt_enqueue() without either
43162306a36Sopenharmony_ci	 * svc_xprt_enqueue() recognizing that the conditions below
43262306a36Sopenharmony_ci	 * are satisfied, and we could stall indefinitely:
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	smp_rmb();
43562306a36Sopenharmony_ci	xpt_flags = READ_ONCE(xprt->xpt_flags);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	trace_svc_xprt_enqueue(xprt, xpt_flags);
43862306a36Sopenharmony_ci	if (xpt_flags & BIT(XPT_BUSY))
43962306a36Sopenharmony_ci		return false;
44062306a36Sopenharmony_ci	if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE) | BIT(XPT_HANDSHAKE)))
44162306a36Sopenharmony_ci		return true;
44262306a36Sopenharmony_ci	if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) {
44362306a36Sopenharmony_ci		if (xprt->xpt_ops->xpo_has_wspace(xprt) &&
44462306a36Sopenharmony_ci		    svc_xprt_slots_in_range(xprt))
44562306a36Sopenharmony_ci			return true;
44662306a36Sopenharmony_ci		trace_svc_xprt_no_write_space(xprt);
44762306a36Sopenharmony_ci		return false;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci	return false;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * svc_xprt_enqueue - Queue a transport on an idle nfsd thread
45462306a36Sopenharmony_ci * @xprt: transport with data pending
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci */
45762306a36Sopenharmony_civoid svc_xprt_enqueue(struct svc_xprt *xprt)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct svc_pool *pool;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (!svc_xprt_ready(xprt))
46262306a36Sopenharmony_ci		return;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Mark transport as busy. It will remain in this state until
46562306a36Sopenharmony_ci	 * the provider calls svc_xprt_received. We update XPT_BUSY
46662306a36Sopenharmony_ci	 * atomically because it also guards against trying to enqueue
46762306a36Sopenharmony_ci	 * the transport twice.
46862306a36Sopenharmony_ci	 */
46962306a36Sopenharmony_ci	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
47062306a36Sopenharmony_ci		return;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	pool = svc_pool_for_cpu(xprt->xpt_server);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	percpu_counter_inc(&pool->sp_sockets_queued);
47562306a36Sopenharmony_ci	spin_lock_bh(&pool->sp_lock);
47662306a36Sopenharmony_ci	list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
47762306a36Sopenharmony_ci	spin_unlock_bh(&pool->sp_lock);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	svc_pool_wake_idle_thread(pool);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_enqueue);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci/*
48462306a36Sopenharmony_ci * Dequeue the first transport, if there is one.
48562306a36Sopenharmony_ci */
48662306a36Sopenharmony_cistatic struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct svc_xprt	*xprt = NULL;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (list_empty(&pool->sp_sockets))
49162306a36Sopenharmony_ci		goto out;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	spin_lock_bh(&pool->sp_lock);
49462306a36Sopenharmony_ci	if (likely(!list_empty(&pool->sp_sockets))) {
49562306a36Sopenharmony_ci		xprt = list_first_entry(&pool->sp_sockets,
49662306a36Sopenharmony_ci					struct svc_xprt, xpt_ready);
49762306a36Sopenharmony_ci		list_del_init(&xprt->xpt_ready);
49862306a36Sopenharmony_ci		svc_xprt_get(xprt);
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	spin_unlock_bh(&pool->sp_lock);
50162306a36Sopenharmony_ciout:
50262306a36Sopenharmony_ci	return xprt;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci/**
50662306a36Sopenharmony_ci * svc_reserve - change the space reserved for the reply to a request.
50762306a36Sopenharmony_ci * @rqstp:  The request in question
50862306a36Sopenharmony_ci * @space: new max space to reserve
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci * Each request reserves some space on the output queue of the transport
51162306a36Sopenharmony_ci * to make sure the reply fits.  This function reduces that reserved
51262306a36Sopenharmony_ci * space to be the amount of space used already, plus @space.
51362306a36Sopenharmony_ci *
51462306a36Sopenharmony_ci */
51562306a36Sopenharmony_civoid svc_reserve(struct svc_rqst *rqstp, int space)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct svc_xprt *xprt = rqstp->rq_xprt;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	space += rqstp->rq_res.head[0].iov_len;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (xprt && space < rqstp->rq_reserved) {
52262306a36Sopenharmony_ci		atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
52362306a36Sopenharmony_ci		rqstp->rq_reserved = space;
52462306a36Sopenharmony_ci		smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
52562306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_reserve);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic void free_deferred(struct svc_xprt *xprt, struct svc_deferred_req *dr)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	if (!dr)
53362306a36Sopenharmony_ci		return;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	xprt->xpt_ops->xpo_release_ctxt(xprt, dr->xprt_ctxt);
53662306a36Sopenharmony_ci	kfree(dr);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic void svc_xprt_release(struct svc_rqst *rqstp)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct svc_xprt	*xprt = rqstp->rq_xprt;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	xprt->xpt_ops->xpo_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
54462306a36Sopenharmony_ci	rqstp->rq_xprt_ctxt = NULL;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	free_deferred(xprt, rqstp->rq_deferred);
54762306a36Sopenharmony_ci	rqstp->rq_deferred = NULL;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	svc_rqst_release_pages(rqstp);
55062306a36Sopenharmony_ci	rqstp->rq_res.page_len = 0;
55162306a36Sopenharmony_ci	rqstp->rq_res.page_base = 0;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Reset response buffer and release
55462306a36Sopenharmony_ci	 * the reservation.
55562306a36Sopenharmony_ci	 * But first, check that enough space was reserved
55662306a36Sopenharmony_ci	 * for the reply, otherwise we have a bug!
55762306a36Sopenharmony_ci	 */
55862306a36Sopenharmony_ci	if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
55962306a36Sopenharmony_ci		printk(KERN_ERR "RPC request reserved %d but used %d\n",
56062306a36Sopenharmony_ci		       rqstp->rq_reserved,
56162306a36Sopenharmony_ci		       rqstp->rq_res.len);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	rqstp->rq_res.head[0].iov_len = 0;
56462306a36Sopenharmony_ci	svc_reserve(rqstp, 0);
56562306a36Sopenharmony_ci	svc_xprt_release_slot(rqstp);
56662306a36Sopenharmony_ci	rqstp->rq_xprt = NULL;
56762306a36Sopenharmony_ci	svc_xprt_put(xprt);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/**
57162306a36Sopenharmony_ci * svc_wake_up - Wake up a service thread for non-transport work
57262306a36Sopenharmony_ci * @serv: RPC service
57362306a36Sopenharmony_ci *
57462306a36Sopenharmony_ci * Some svc_serv's will have occasional work to do, even when a xprt is not
57562306a36Sopenharmony_ci * waiting to be serviced. This function is there to "kick" a task in one of
57662306a36Sopenharmony_ci * those services so that it can wake up and do that work. Note that we only
57762306a36Sopenharmony_ci * bother with pool 0 as we don't need to wake up more than one thread for
57862306a36Sopenharmony_ci * this purpose.
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_civoid svc_wake_up(struct svc_serv *serv)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct svc_pool *pool = &serv->sv_pools[0];
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	set_bit(SP_TASK_PENDING, &pool->sp_flags);
58562306a36Sopenharmony_ci	svc_pool_wake_idle_thread(pool);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_wake_up);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ciint svc_port_is_privileged(struct sockaddr *sin)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	switch (sin->sa_family) {
59262306a36Sopenharmony_ci	case AF_INET:
59362306a36Sopenharmony_ci		return ntohs(((struct sockaddr_in *)sin)->sin_port)
59462306a36Sopenharmony_ci			< PROT_SOCK;
59562306a36Sopenharmony_ci	case AF_INET6:
59662306a36Sopenharmony_ci		return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
59762306a36Sopenharmony_ci			< PROT_SOCK;
59862306a36Sopenharmony_ci	default:
59962306a36Sopenharmony_ci		return 0;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * Make sure that we don't have too many active connections. If we have,
60562306a36Sopenharmony_ci * something must be dropped. It's not clear what will happen if we allow
60662306a36Sopenharmony_ci * "too many" connections, but when dealing with network-facing software,
60762306a36Sopenharmony_ci * we have to code defensively. Here we do that by imposing hard limits.
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * There's no point in trying to do random drop here for DoS
61062306a36Sopenharmony_ci * prevention. The NFS clients does 1 reconnect in 15 seconds. An
61162306a36Sopenharmony_ci * attacker can easily beat that.
61262306a36Sopenharmony_ci *
61362306a36Sopenharmony_ci * The only somewhat efficient mechanism would be if drop old
61462306a36Sopenharmony_ci * connections from the same IP first. But right now we don't even
61562306a36Sopenharmony_ci * record the client IP in svc_sock.
61662306a36Sopenharmony_ci *
61762306a36Sopenharmony_ci * single-threaded services that expect a lot of clients will probably
61862306a36Sopenharmony_ci * need to set sv_maxconn to override the default value which is based
61962306a36Sopenharmony_ci * on the number of threads
62062306a36Sopenharmony_ci */
62162306a36Sopenharmony_cistatic void svc_check_conn_limits(struct svc_serv *serv)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
62462306a36Sopenharmony_ci				(serv->sv_nrthreads+3) * 20;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (serv->sv_tmpcnt > limit) {
62762306a36Sopenharmony_ci		struct svc_xprt *xprt = NULL;
62862306a36Sopenharmony_ci		spin_lock_bh(&serv->sv_lock);
62962306a36Sopenharmony_ci		if (!list_empty(&serv->sv_tempsocks)) {
63062306a36Sopenharmony_ci			/* Try to help the admin */
63162306a36Sopenharmony_ci			net_notice_ratelimited("%s: too many open connections, consider increasing the %s\n",
63262306a36Sopenharmony_ci					       serv->sv_name, serv->sv_maxconn ?
63362306a36Sopenharmony_ci					       "max number of connections" :
63462306a36Sopenharmony_ci					       "number of threads");
63562306a36Sopenharmony_ci			/*
63662306a36Sopenharmony_ci			 * Always select the oldest connection. It's not fair,
63762306a36Sopenharmony_ci			 * but so is life
63862306a36Sopenharmony_ci			 */
63962306a36Sopenharmony_ci			xprt = list_entry(serv->sv_tempsocks.prev,
64062306a36Sopenharmony_ci					  struct svc_xprt,
64162306a36Sopenharmony_ci					  xpt_list);
64262306a36Sopenharmony_ci			set_bit(XPT_CLOSE, &xprt->xpt_flags);
64362306a36Sopenharmony_ci			svc_xprt_get(xprt);
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci		spin_unlock_bh(&serv->sv_lock);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		if (xprt) {
64862306a36Sopenharmony_ci			svc_xprt_enqueue(xprt);
64962306a36Sopenharmony_ci			svc_xprt_put(xprt);
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic bool svc_alloc_arg(struct svc_rqst *rqstp)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct svc_serv *serv = rqstp->rq_server;
65762306a36Sopenharmony_ci	struct xdr_buf *arg = &rqstp->rq_arg;
65862306a36Sopenharmony_ci	unsigned long pages, filled, ret;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
66162306a36Sopenharmony_ci	if (pages > RPCSVC_MAXPAGES) {
66262306a36Sopenharmony_ci		pr_warn_once("svc: warning: pages=%lu > RPCSVC_MAXPAGES=%lu\n",
66362306a36Sopenharmony_ci			     pages, RPCSVC_MAXPAGES);
66462306a36Sopenharmony_ci		/* use as many pages as possible */
66562306a36Sopenharmony_ci		pages = RPCSVC_MAXPAGES;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	for (filled = 0; filled < pages; filled = ret) {
66962306a36Sopenharmony_ci		ret = alloc_pages_bulk_array(GFP_KERNEL, pages,
67062306a36Sopenharmony_ci					     rqstp->rq_pages);
67162306a36Sopenharmony_ci		if (ret > filled)
67262306a36Sopenharmony_ci			/* Made progress, don't sleep yet */
67362306a36Sopenharmony_ci			continue;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		set_current_state(TASK_IDLE);
67662306a36Sopenharmony_ci		if (kthread_should_stop()) {
67762306a36Sopenharmony_ci			set_current_state(TASK_RUNNING);
67862306a36Sopenharmony_ci			return false;
67962306a36Sopenharmony_ci		}
68062306a36Sopenharmony_ci		trace_svc_alloc_arg_err(pages, ret);
68162306a36Sopenharmony_ci		memalloc_retry_wait(GFP_KERNEL);
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci	rqstp->rq_page_end = &rqstp->rq_pages[pages];
68462306a36Sopenharmony_ci	rqstp->rq_pages[pages] = NULL; /* this might be seen in nfsd_splice_actor() */
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* Make arg->head point to first page and arg->pages point to rest */
68762306a36Sopenharmony_ci	arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
68862306a36Sopenharmony_ci	arg->head[0].iov_len = PAGE_SIZE;
68962306a36Sopenharmony_ci	arg->pages = rqstp->rq_pages + 1;
69062306a36Sopenharmony_ci	arg->page_base = 0;
69162306a36Sopenharmony_ci	/* save at least one page for response */
69262306a36Sopenharmony_ci	arg->page_len = (pages-2)*PAGE_SIZE;
69362306a36Sopenharmony_ci	arg->len = (pages-1)*PAGE_SIZE;
69462306a36Sopenharmony_ci	arg->tail[0].iov_len = 0;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	rqstp->rq_xid = xdr_zero;
69762306a36Sopenharmony_ci	return true;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic bool
70162306a36Sopenharmony_cirqst_should_sleep(struct svc_rqst *rqstp)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	struct svc_pool		*pool = rqstp->rq_pool;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* did someone call svc_wake_up? */
70662306a36Sopenharmony_ci	if (test_bit(SP_TASK_PENDING, &pool->sp_flags))
70762306a36Sopenharmony_ci		return false;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* was a socket queued? */
71062306a36Sopenharmony_ci	if (!list_empty(&pool->sp_sockets))
71162306a36Sopenharmony_ci		return false;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* are we shutting down? */
71462306a36Sopenharmony_ci	if (kthread_should_stop())
71562306a36Sopenharmony_ci		return false;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* are we freezing? */
71862306a36Sopenharmony_ci	if (freezing(current))
71962306a36Sopenharmony_ci		return false;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	return true;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct svc_pool		*pool = rqstp->rq_pool;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* rq_xprt should be clear on entry */
72962306a36Sopenharmony_ci	WARN_ON_ONCE(rqstp->rq_xprt);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	rqstp->rq_xprt = svc_xprt_dequeue(pool);
73262306a36Sopenharmony_ci	if (rqstp->rq_xprt)
73362306a36Sopenharmony_ci		goto out_found;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	set_current_state(TASK_IDLE);
73662306a36Sopenharmony_ci	smp_mb__before_atomic();
73762306a36Sopenharmony_ci	clear_bit(SP_CONGESTED, &pool->sp_flags);
73862306a36Sopenharmony_ci	clear_bit(RQ_BUSY, &rqstp->rq_flags);
73962306a36Sopenharmony_ci	smp_mb__after_atomic();
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (likely(rqst_should_sleep(rqstp)))
74262306a36Sopenharmony_ci		schedule();
74362306a36Sopenharmony_ci	else
74462306a36Sopenharmony_ci		__set_current_state(TASK_RUNNING);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	try_to_freeze();
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	set_bit(RQ_BUSY, &rqstp->rq_flags);
74962306a36Sopenharmony_ci	smp_mb__after_atomic();
75062306a36Sopenharmony_ci	clear_bit(SP_TASK_PENDING, &pool->sp_flags);
75162306a36Sopenharmony_ci	rqstp->rq_xprt = svc_xprt_dequeue(pool);
75262306a36Sopenharmony_ci	if (rqstp->rq_xprt)
75362306a36Sopenharmony_ci		goto out_found;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (kthread_should_stop())
75662306a36Sopenharmony_ci		return NULL;
75762306a36Sopenharmony_ci	return NULL;
75862306a36Sopenharmony_ciout_found:
75962306a36Sopenharmony_ci	clear_bit(SP_TASK_PENDING, &pool->sp_flags);
76062306a36Sopenharmony_ci	/* Normally we will wait up to 5 seconds for any required
76162306a36Sopenharmony_ci	 * cache information to be provided.
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	if (!test_bit(SP_CONGESTED, &pool->sp_flags))
76462306a36Sopenharmony_ci		rqstp->rq_chandle.thread_wait = 5*HZ;
76562306a36Sopenharmony_ci	else
76662306a36Sopenharmony_ci		rqstp->rq_chandle.thread_wait = 1*HZ;
76762306a36Sopenharmony_ci	trace_svc_xprt_dequeue(rqstp);
76862306a36Sopenharmony_ci	return rqstp->rq_xprt;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
77462306a36Sopenharmony_ci	set_bit(XPT_TEMP, &newxpt->xpt_flags);
77562306a36Sopenharmony_ci	list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
77662306a36Sopenharmony_ci	serv->sv_tmpcnt++;
77762306a36Sopenharmony_ci	if (serv->sv_temptimer.function == NULL) {
77862306a36Sopenharmony_ci		/* setup timer to age temp transports */
77962306a36Sopenharmony_ci		serv->sv_temptimer.function = svc_age_temp_xprts;
78062306a36Sopenharmony_ci		mod_timer(&serv->sv_temptimer,
78162306a36Sopenharmony_ci			  jiffies + svc_conn_age_period * HZ);
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
78462306a36Sopenharmony_ci	svc_xprt_received(newxpt);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct svc_serv *serv = rqstp->rq_server;
79062306a36Sopenharmony_ci	int len = 0;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
79362306a36Sopenharmony_ci		if (test_and_clear_bit(XPT_KILL_TEMP, &xprt->xpt_flags))
79462306a36Sopenharmony_ci			xprt->xpt_ops->xpo_kill_temp_xprt(xprt);
79562306a36Sopenharmony_ci		svc_delete_xprt(xprt);
79662306a36Sopenharmony_ci		/* Leave XPT_BUSY set on the dead xprt: */
79762306a36Sopenharmony_ci		goto out;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci	if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
80062306a36Sopenharmony_ci		struct svc_xprt *newxpt;
80162306a36Sopenharmony_ci		/*
80262306a36Sopenharmony_ci		 * We know this module_get will succeed because the
80362306a36Sopenharmony_ci		 * listener holds a reference too
80462306a36Sopenharmony_ci		 */
80562306a36Sopenharmony_ci		__module_get(xprt->xpt_class->xcl_owner);
80662306a36Sopenharmony_ci		svc_check_conn_limits(xprt->xpt_server);
80762306a36Sopenharmony_ci		newxpt = xprt->xpt_ops->xpo_accept(xprt);
80862306a36Sopenharmony_ci		if (newxpt) {
80962306a36Sopenharmony_ci			newxpt->xpt_cred = get_cred(xprt->xpt_cred);
81062306a36Sopenharmony_ci			svc_add_new_temp_xprt(serv, newxpt);
81162306a36Sopenharmony_ci			trace_svc_xprt_accept(newxpt, serv->sv_name);
81262306a36Sopenharmony_ci		} else {
81362306a36Sopenharmony_ci			module_put(xprt->xpt_class->xcl_owner);
81462306a36Sopenharmony_ci		}
81562306a36Sopenharmony_ci		svc_xprt_received(xprt);
81662306a36Sopenharmony_ci	} else if (test_bit(XPT_HANDSHAKE, &xprt->xpt_flags)) {
81762306a36Sopenharmony_ci		xprt->xpt_ops->xpo_handshake(xprt);
81862306a36Sopenharmony_ci		svc_xprt_received(xprt);
81962306a36Sopenharmony_ci	} else if (svc_xprt_reserve_slot(rqstp, xprt)) {
82062306a36Sopenharmony_ci		/* XPT_DATA|XPT_DEFERRED case: */
82162306a36Sopenharmony_ci		rqstp->rq_deferred = svc_deferred_dequeue(xprt);
82262306a36Sopenharmony_ci		if (rqstp->rq_deferred)
82362306a36Sopenharmony_ci			len = svc_deferred_recv(rqstp);
82462306a36Sopenharmony_ci		else
82562306a36Sopenharmony_ci			len = xprt->xpt_ops->xpo_recvfrom(rqstp);
82662306a36Sopenharmony_ci		rqstp->rq_reserved = serv->sv_max_mesg;
82762306a36Sopenharmony_ci		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
82862306a36Sopenharmony_ci	} else
82962306a36Sopenharmony_ci		svc_xprt_received(xprt);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ciout:
83262306a36Sopenharmony_ci	return len;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci/**
83662306a36Sopenharmony_ci * svc_recv - Receive and process the next request on any transport
83762306a36Sopenharmony_ci * @rqstp: an idle RPC service thread
83862306a36Sopenharmony_ci *
83962306a36Sopenharmony_ci * This code is carefully organised not to touch any cachelines in
84062306a36Sopenharmony_ci * the shared svc_serv structure, only cachelines in the local
84162306a36Sopenharmony_ci * svc_pool.
84262306a36Sopenharmony_ci */
84362306a36Sopenharmony_civoid svc_recv(struct svc_rqst *rqstp)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct svc_xprt		*xprt = NULL;
84662306a36Sopenharmony_ci	struct svc_serv		*serv = rqstp->rq_server;
84762306a36Sopenharmony_ci	int			len;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (!svc_alloc_arg(rqstp))
85062306a36Sopenharmony_ci		goto out;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	try_to_freeze();
85362306a36Sopenharmony_ci	cond_resched();
85462306a36Sopenharmony_ci	if (kthread_should_stop())
85562306a36Sopenharmony_ci		goto out;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	xprt = svc_get_next_xprt(rqstp);
85862306a36Sopenharmony_ci	if (!xprt)
85962306a36Sopenharmony_ci		goto out;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	len = svc_handle_xprt(rqstp, xprt);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* No data, incomplete (TCP) read, or accept() */
86462306a36Sopenharmony_ci	if (len <= 0)
86562306a36Sopenharmony_ci		goto out_release;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	trace_svc_xdr_recvfrom(&rqstp->rq_arg);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	clear_bit(XPT_OLD, &xprt->xpt_flags);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	rqstp->rq_chandle.defer = svc_defer;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (serv->sv_stats)
87462306a36Sopenharmony_ci		serv->sv_stats->netcnt++;
87562306a36Sopenharmony_ci	percpu_counter_inc(&rqstp->rq_pool->sp_messages_arrived);
87662306a36Sopenharmony_ci	rqstp->rq_stime = ktime_get();
87762306a36Sopenharmony_ci	svc_process(rqstp);
87862306a36Sopenharmony_ciout:
87962306a36Sopenharmony_ci	return;
88062306a36Sopenharmony_ciout_release:
88162306a36Sopenharmony_ci	rqstp->rq_res.len = 0;
88262306a36Sopenharmony_ci	svc_xprt_release(rqstp);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_recv);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/*
88762306a36Sopenharmony_ci * Drop request
88862306a36Sopenharmony_ci */
88962306a36Sopenharmony_civoid svc_drop(struct svc_rqst *rqstp)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	trace_svc_drop(rqstp);
89262306a36Sopenharmony_ci	svc_xprt_release(rqstp);
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_drop);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci/**
89762306a36Sopenharmony_ci * svc_send - Return reply to client
89862306a36Sopenharmony_ci * @rqstp: RPC transaction context
89962306a36Sopenharmony_ci *
90062306a36Sopenharmony_ci */
90162306a36Sopenharmony_civoid svc_send(struct svc_rqst *rqstp)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct svc_xprt	*xprt;
90462306a36Sopenharmony_ci	struct xdr_buf	*xb;
90562306a36Sopenharmony_ci	int status;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	xprt = rqstp->rq_xprt;
90862306a36Sopenharmony_ci	if (!xprt)
90962306a36Sopenharmony_ci		return;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	/* calculate over-all length */
91262306a36Sopenharmony_ci	xb = &rqstp->rq_res;
91362306a36Sopenharmony_ci	xb->len = xb->head[0].iov_len +
91462306a36Sopenharmony_ci		xb->page_len +
91562306a36Sopenharmony_ci		xb->tail[0].iov_len;
91662306a36Sopenharmony_ci	trace_svc_xdr_sendto(rqstp->rq_xid, xb);
91762306a36Sopenharmony_ci	trace_svc_stats_latency(rqstp);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	status = xprt->xpt_ops->xpo_sendto(rqstp);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	trace_svc_send(rqstp, status);
92262306a36Sopenharmony_ci	svc_xprt_release(rqstp);
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/*
92662306a36Sopenharmony_ci * Timer function to close old temporary transports, using
92762306a36Sopenharmony_ci * a mark-and-sweep algorithm.
92862306a36Sopenharmony_ci */
92962306a36Sopenharmony_cistatic void svc_age_temp_xprts(struct timer_list *t)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	struct svc_serv *serv = from_timer(serv, t, sv_temptimer);
93262306a36Sopenharmony_ci	struct svc_xprt *xprt;
93362306a36Sopenharmony_ci	struct list_head *le, *next;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	dprintk("svc_age_temp_xprts\n");
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (!spin_trylock_bh(&serv->sv_lock)) {
93862306a36Sopenharmony_ci		/* busy, try again 1 sec later */
93962306a36Sopenharmony_ci		dprintk("svc_age_temp_xprts: busy\n");
94062306a36Sopenharmony_ci		mod_timer(&serv->sv_temptimer, jiffies + HZ);
94162306a36Sopenharmony_ci		return;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	list_for_each_safe(le, next, &serv->sv_tempsocks) {
94562306a36Sopenharmony_ci		xprt = list_entry(le, struct svc_xprt, xpt_list);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		/* First time through, just mark it OLD. Second time
94862306a36Sopenharmony_ci		 * through, close it. */
94962306a36Sopenharmony_ci		if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags))
95062306a36Sopenharmony_ci			continue;
95162306a36Sopenharmony_ci		if (kref_read(&xprt->xpt_ref) > 1 ||
95262306a36Sopenharmony_ci		    test_bit(XPT_BUSY, &xprt->xpt_flags))
95362306a36Sopenharmony_ci			continue;
95462306a36Sopenharmony_ci		list_del_init(le);
95562306a36Sopenharmony_ci		set_bit(XPT_CLOSE, &xprt->xpt_flags);
95662306a36Sopenharmony_ci		dprintk("queuing xprt %p for closing\n", xprt);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		/* a thread will dequeue and close it soon */
95962306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci/* Close temporary transports whose xpt_local matches server_addr immediately
96762306a36Sopenharmony_ci * instead of waiting for them to be picked up by the timer.
96862306a36Sopenharmony_ci *
96962306a36Sopenharmony_ci * This is meant to be called from a notifier_block that runs when an ip
97062306a36Sopenharmony_ci * address is deleted.
97162306a36Sopenharmony_ci */
97262306a36Sopenharmony_civoid svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	struct svc_xprt *xprt;
97562306a36Sopenharmony_ci	struct list_head *le, *next;
97662306a36Sopenharmony_ci	LIST_HEAD(to_be_closed);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
97962306a36Sopenharmony_ci	list_for_each_safe(le, next, &serv->sv_tempsocks) {
98062306a36Sopenharmony_ci		xprt = list_entry(le, struct svc_xprt, xpt_list);
98162306a36Sopenharmony_ci		if (rpc_cmp_addr(server_addr, (struct sockaddr *)
98262306a36Sopenharmony_ci				&xprt->xpt_local)) {
98362306a36Sopenharmony_ci			dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
98462306a36Sopenharmony_ci			list_move(le, &to_be_closed);
98562306a36Sopenharmony_ci		}
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	while (!list_empty(&to_be_closed)) {
99062306a36Sopenharmony_ci		le = to_be_closed.next;
99162306a36Sopenharmony_ci		list_del_init(le);
99262306a36Sopenharmony_ci		xprt = list_entry(le, struct svc_xprt, xpt_list);
99362306a36Sopenharmony_ci		set_bit(XPT_CLOSE, &xprt->xpt_flags);
99462306a36Sopenharmony_ci		set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
99562306a36Sopenharmony_ci		dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
99662306a36Sopenharmony_ci				xprt);
99762306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic void call_xpt_users(struct svc_xprt *xprt)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct svc_xpt_user *u;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	spin_lock(&xprt->xpt_lock);
100762306a36Sopenharmony_ci	while (!list_empty(&xprt->xpt_users)) {
100862306a36Sopenharmony_ci		u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list);
100962306a36Sopenharmony_ci		list_del_init(&u->list);
101062306a36Sopenharmony_ci		u->callback(u);
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci	spin_unlock(&xprt->xpt_lock);
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci/*
101662306a36Sopenharmony_ci * Remove a dead transport
101762306a36Sopenharmony_ci */
101862306a36Sopenharmony_cistatic void svc_delete_xprt(struct svc_xprt *xprt)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	struct svc_serv	*serv = xprt->xpt_server;
102162306a36Sopenharmony_ci	struct svc_deferred_req *dr;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
102462306a36Sopenharmony_ci		return;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	trace_svc_xprt_detach(xprt);
102762306a36Sopenharmony_ci	xprt->xpt_ops->xpo_detach(xprt);
102862306a36Sopenharmony_ci	if (xprt->xpt_bc_xprt)
102962306a36Sopenharmony_ci		xprt->xpt_bc_xprt->ops->close(xprt->xpt_bc_xprt);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
103262306a36Sopenharmony_ci	list_del_init(&xprt->xpt_list);
103362306a36Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&xprt->xpt_ready));
103462306a36Sopenharmony_ci	if (test_bit(XPT_TEMP, &xprt->xpt_flags))
103562306a36Sopenharmony_ci		serv->sv_tmpcnt--;
103662306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	while ((dr = svc_deferred_dequeue(xprt)) != NULL)
103962306a36Sopenharmony_ci		free_deferred(xprt, dr);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	call_xpt_users(xprt);
104262306a36Sopenharmony_ci	svc_xprt_put(xprt);
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci/**
104662306a36Sopenharmony_ci * svc_xprt_close - Close a client connection
104762306a36Sopenharmony_ci * @xprt: transport to disconnect
104862306a36Sopenharmony_ci *
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_civoid svc_xprt_close(struct svc_xprt *xprt)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	trace_svc_xprt_close(xprt);
105362306a36Sopenharmony_ci	set_bit(XPT_CLOSE, &xprt->xpt_flags);
105462306a36Sopenharmony_ci	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
105562306a36Sopenharmony_ci		/* someone else will have to effect the close */
105662306a36Sopenharmony_ci		return;
105762306a36Sopenharmony_ci	/*
105862306a36Sopenharmony_ci	 * We expect svc_close_xprt() to work even when no threads are
105962306a36Sopenharmony_ci	 * running (e.g., while configuring the server before starting
106062306a36Sopenharmony_ci	 * any threads), so if the transport isn't busy, we delete
106162306a36Sopenharmony_ci	 * it ourself:
106262306a36Sopenharmony_ci	 */
106362306a36Sopenharmony_ci	svc_delete_xprt(xprt);
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_close);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	struct svc_xprt *xprt;
107062306a36Sopenharmony_ci	int ret = 0;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
107362306a36Sopenharmony_ci	list_for_each_entry(xprt, xprt_list, xpt_list) {
107462306a36Sopenharmony_ci		if (xprt->xpt_net != net)
107562306a36Sopenharmony_ci			continue;
107662306a36Sopenharmony_ci		ret++;
107762306a36Sopenharmony_ci		set_bit(XPT_CLOSE, &xprt->xpt_flags);
107862306a36Sopenharmony_ci		svc_xprt_enqueue(xprt);
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
108162306a36Sopenharmony_ci	return ret;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic struct svc_xprt *svc_dequeue_net(struct svc_serv *serv, struct net *net)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct svc_pool *pool;
108762306a36Sopenharmony_ci	struct svc_xprt *xprt;
108862306a36Sopenharmony_ci	struct svc_xprt *tmp;
108962306a36Sopenharmony_ci	int i;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	for (i = 0; i < serv->sv_nrpools; i++) {
109262306a36Sopenharmony_ci		pool = &serv->sv_pools[i];
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		spin_lock_bh(&pool->sp_lock);
109562306a36Sopenharmony_ci		list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) {
109662306a36Sopenharmony_ci			if (xprt->xpt_net != net)
109762306a36Sopenharmony_ci				continue;
109862306a36Sopenharmony_ci			list_del_init(&xprt->xpt_ready);
109962306a36Sopenharmony_ci			spin_unlock_bh(&pool->sp_lock);
110062306a36Sopenharmony_ci			return xprt;
110162306a36Sopenharmony_ci		}
110262306a36Sopenharmony_ci		spin_unlock_bh(&pool->sp_lock);
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci	return NULL;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	struct svc_xprt *xprt;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	while ((xprt = svc_dequeue_net(serv, net))) {
111262306a36Sopenharmony_ci		set_bit(XPT_CLOSE, &xprt->xpt_flags);
111362306a36Sopenharmony_ci		svc_delete_xprt(xprt);
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci/**
111862306a36Sopenharmony_ci * svc_xprt_destroy_all - Destroy transports associated with @serv
111962306a36Sopenharmony_ci * @serv: RPC service to be shut down
112062306a36Sopenharmony_ci * @net: target network namespace
112162306a36Sopenharmony_ci *
112262306a36Sopenharmony_ci * Server threads may still be running (especially in the case where the
112362306a36Sopenharmony_ci * service is still running in other network namespaces).
112462306a36Sopenharmony_ci *
112562306a36Sopenharmony_ci * So we shut down sockets the same way we would on a running server, by
112662306a36Sopenharmony_ci * setting XPT_CLOSE, enqueuing, and letting a thread pick it up to do
112762306a36Sopenharmony_ci * the close.  In the case there are no such other threads,
112862306a36Sopenharmony_ci * threads running, svc_clean_up_xprts() does a simple version of a
112962306a36Sopenharmony_ci * server's main event loop, and in the case where there are other
113062306a36Sopenharmony_ci * threads, we may need to wait a little while and then check again to
113162306a36Sopenharmony_ci * see if they're done.
113262306a36Sopenharmony_ci */
113362306a36Sopenharmony_civoid svc_xprt_destroy_all(struct svc_serv *serv, struct net *net)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	int delay = 0;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	while (svc_close_list(serv, &serv->sv_permsocks, net) +
113862306a36Sopenharmony_ci	       svc_close_list(serv, &serv->sv_tempsocks, net)) {
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		svc_clean_up_xprts(serv, net);
114162306a36Sopenharmony_ci		msleep(delay++);
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_destroy_all);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci/*
114762306a36Sopenharmony_ci * Handle defer and revisit of requests
114862306a36Sopenharmony_ci */
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic void svc_revisit(struct cache_deferred_req *dreq, int too_many)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	struct svc_deferred_req *dr =
115362306a36Sopenharmony_ci		container_of(dreq, struct svc_deferred_req, handle);
115462306a36Sopenharmony_ci	struct svc_xprt *xprt = dr->xprt;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	spin_lock(&xprt->xpt_lock);
115762306a36Sopenharmony_ci	set_bit(XPT_DEFERRED, &xprt->xpt_flags);
115862306a36Sopenharmony_ci	if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
115962306a36Sopenharmony_ci		spin_unlock(&xprt->xpt_lock);
116062306a36Sopenharmony_ci		trace_svc_defer_drop(dr);
116162306a36Sopenharmony_ci		free_deferred(xprt, dr);
116262306a36Sopenharmony_ci		svc_xprt_put(xprt);
116362306a36Sopenharmony_ci		return;
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci	dr->xprt = NULL;
116662306a36Sopenharmony_ci	list_add(&dr->handle.recent, &xprt->xpt_deferred);
116762306a36Sopenharmony_ci	spin_unlock(&xprt->xpt_lock);
116862306a36Sopenharmony_ci	trace_svc_defer_queue(dr);
116962306a36Sopenharmony_ci	svc_xprt_enqueue(xprt);
117062306a36Sopenharmony_ci	svc_xprt_put(xprt);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci/*
117462306a36Sopenharmony_ci * Save the request off for later processing. The request buffer looks
117562306a36Sopenharmony_ci * like this:
117662306a36Sopenharmony_ci *
117762306a36Sopenharmony_ci * <xprt-header><rpc-header><rpc-pagelist><rpc-tail>
117862306a36Sopenharmony_ci *
117962306a36Sopenharmony_ci * This code can only handle requests that consist of an xprt-header
118062306a36Sopenharmony_ci * and rpc-header.
118162306a36Sopenharmony_ci */
118262306a36Sopenharmony_cistatic struct cache_deferred_req *svc_defer(struct cache_req *req)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
118562306a36Sopenharmony_ci	struct svc_deferred_req *dr;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	if (rqstp->rq_arg.page_len || !test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags))
118862306a36Sopenharmony_ci		return NULL; /* if more than a page, give up FIXME */
118962306a36Sopenharmony_ci	if (rqstp->rq_deferred) {
119062306a36Sopenharmony_ci		dr = rqstp->rq_deferred;
119162306a36Sopenharmony_ci		rqstp->rq_deferred = NULL;
119262306a36Sopenharmony_ci	} else {
119362306a36Sopenharmony_ci		size_t skip;
119462306a36Sopenharmony_ci		size_t size;
119562306a36Sopenharmony_ci		/* FIXME maybe discard if size too large */
119662306a36Sopenharmony_ci		size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
119762306a36Sopenharmony_ci		dr = kmalloc(size, GFP_KERNEL);
119862306a36Sopenharmony_ci		if (dr == NULL)
119962306a36Sopenharmony_ci			return NULL;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci		dr->handle.owner = rqstp->rq_server;
120262306a36Sopenharmony_ci		dr->prot = rqstp->rq_prot;
120362306a36Sopenharmony_ci		memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
120462306a36Sopenharmony_ci		dr->addrlen = rqstp->rq_addrlen;
120562306a36Sopenharmony_ci		dr->daddr = rqstp->rq_daddr;
120662306a36Sopenharmony_ci		dr->argslen = rqstp->rq_arg.len >> 2;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci		/* back up head to the start of the buffer and copy */
120962306a36Sopenharmony_ci		skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
121062306a36Sopenharmony_ci		memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
121162306a36Sopenharmony_ci		       dr->argslen << 2);
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci	dr->xprt_ctxt = rqstp->rq_xprt_ctxt;
121462306a36Sopenharmony_ci	rqstp->rq_xprt_ctxt = NULL;
121562306a36Sopenharmony_ci	trace_svc_defer(rqstp);
121662306a36Sopenharmony_ci	svc_xprt_get(rqstp->rq_xprt);
121762306a36Sopenharmony_ci	dr->xprt = rqstp->rq_xprt;
121862306a36Sopenharmony_ci	set_bit(RQ_DROPME, &rqstp->rq_flags);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	dr->handle.revisit = svc_revisit;
122162306a36Sopenharmony_ci	return &dr->handle;
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci/*
122562306a36Sopenharmony_ci * recv data from a deferred request into an active one
122662306a36Sopenharmony_ci */
122762306a36Sopenharmony_cistatic noinline int svc_deferred_recv(struct svc_rqst *rqstp)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	struct svc_deferred_req *dr = rqstp->rq_deferred;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	trace_svc_defer_recv(dr);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* setup iov_base past transport header */
123462306a36Sopenharmony_ci	rqstp->rq_arg.head[0].iov_base = dr->args;
123562306a36Sopenharmony_ci	/* The iov_len does not include the transport header bytes */
123662306a36Sopenharmony_ci	rqstp->rq_arg.head[0].iov_len = dr->argslen << 2;
123762306a36Sopenharmony_ci	rqstp->rq_arg.page_len = 0;
123862306a36Sopenharmony_ci	/* The rq_arg.len includes the transport header bytes */
123962306a36Sopenharmony_ci	rqstp->rq_arg.len     = dr->argslen << 2;
124062306a36Sopenharmony_ci	rqstp->rq_prot        = dr->prot;
124162306a36Sopenharmony_ci	memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
124262306a36Sopenharmony_ci	rqstp->rq_addrlen     = dr->addrlen;
124362306a36Sopenharmony_ci	/* Save off transport header len in case we get deferred again */
124462306a36Sopenharmony_ci	rqstp->rq_daddr       = dr->daddr;
124562306a36Sopenharmony_ci	rqstp->rq_respages    = rqstp->rq_pages;
124662306a36Sopenharmony_ci	rqstp->rq_xprt_ctxt   = dr->xprt_ctxt;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	dr->xprt_ctxt = NULL;
124962306a36Sopenharmony_ci	svc_xprt_received(rqstp->rq_xprt);
125062306a36Sopenharmony_ci	return dr->argslen << 2;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct svc_deferred_req *dr = NULL;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
125962306a36Sopenharmony_ci		return NULL;
126062306a36Sopenharmony_ci	spin_lock(&xprt->xpt_lock);
126162306a36Sopenharmony_ci	if (!list_empty(&xprt->xpt_deferred)) {
126262306a36Sopenharmony_ci		dr = list_entry(xprt->xpt_deferred.next,
126362306a36Sopenharmony_ci				struct svc_deferred_req,
126462306a36Sopenharmony_ci				handle.recent);
126562306a36Sopenharmony_ci		list_del_init(&dr->handle.recent);
126662306a36Sopenharmony_ci	} else
126762306a36Sopenharmony_ci		clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
126862306a36Sopenharmony_ci	spin_unlock(&xprt->xpt_lock);
126962306a36Sopenharmony_ci	return dr;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/**
127362306a36Sopenharmony_ci * svc_find_xprt - find an RPC transport instance
127462306a36Sopenharmony_ci * @serv: pointer to svc_serv to search
127562306a36Sopenharmony_ci * @xcl_name: C string containing transport's class name
127662306a36Sopenharmony_ci * @net: owner net pointer
127762306a36Sopenharmony_ci * @af: Address family of transport's local address
127862306a36Sopenharmony_ci * @port: transport's IP port number
127962306a36Sopenharmony_ci *
128062306a36Sopenharmony_ci * Return the transport instance pointer for the endpoint accepting
128162306a36Sopenharmony_ci * connections/peer traffic from the specified transport class,
128262306a36Sopenharmony_ci * address family and port.
128362306a36Sopenharmony_ci *
128462306a36Sopenharmony_ci * Specifying 0 for the address family or port is effectively a
128562306a36Sopenharmony_ci * wild-card, and will result in matching the first transport in the
128662306a36Sopenharmony_ci * service's list that has a matching class name.
128762306a36Sopenharmony_ci */
128862306a36Sopenharmony_cistruct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
128962306a36Sopenharmony_ci			       struct net *net, const sa_family_t af,
129062306a36Sopenharmony_ci			       const unsigned short port)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	struct svc_xprt *xprt;
129362306a36Sopenharmony_ci	struct svc_xprt *found = NULL;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* Sanity check the args */
129662306a36Sopenharmony_ci	if (serv == NULL || xcl_name == NULL)
129762306a36Sopenharmony_ci		return found;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
130062306a36Sopenharmony_ci	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
130162306a36Sopenharmony_ci		if (xprt->xpt_net != net)
130262306a36Sopenharmony_ci			continue;
130362306a36Sopenharmony_ci		if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
130462306a36Sopenharmony_ci			continue;
130562306a36Sopenharmony_ci		if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
130662306a36Sopenharmony_ci			continue;
130762306a36Sopenharmony_ci		if (port != 0 && port != svc_xprt_local_port(xprt))
130862306a36Sopenharmony_ci			continue;
130962306a36Sopenharmony_ci		found = xprt;
131062306a36Sopenharmony_ci		svc_xprt_get(xprt);
131162306a36Sopenharmony_ci		break;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
131462306a36Sopenharmony_ci	return found;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_find_xprt);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic int svc_one_xprt_name(const struct svc_xprt *xprt,
131962306a36Sopenharmony_ci			     char *pos, int remaining)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	int len;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	len = snprintf(pos, remaining, "%s %u\n",
132462306a36Sopenharmony_ci			xprt->xpt_class->xcl_name,
132562306a36Sopenharmony_ci			svc_xprt_local_port(xprt));
132662306a36Sopenharmony_ci	if (len >= remaining)
132762306a36Sopenharmony_ci		return -ENAMETOOLONG;
132862306a36Sopenharmony_ci	return len;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci/**
133262306a36Sopenharmony_ci * svc_xprt_names - format a buffer with a list of transport names
133362306a36Sopenharmony_ci * @serv: pointer to an RPC service
133462306a36Sopenharmony_ci * @buf: pointer to a buffer to be filled in
133562306a36Sopenharmony_ci * @buflen: length of buffer to be filled in
133662306a36Sopenharmony_ci *
133762306a36Sopenharmony_ci * Fills in @buf with a string containing a list of transport names,
133862306a36Sopenharmony_ci * each name terminated with '\n'.
133962306a36Sopenharmony_ci *
134062306a36Sopenharmony_ci * Returns positive length of the filled-in string on success; otherwise
134162306a36Sopenharmony_ci * a negative errno value is returned if an error occurs.
134262306a36Sopenharmony_ci */
134362306a36Sopenharmony_ciint svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	struct svc_xprt *xprt;
134662306a36Sopenharmony_ci	int len, totlen;
134762306a36Sopenharmony_ci	char *pos;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* Sanity check args */
135062306a36Sopenharmony_ci	if (!serv)
135162306a36Sopenharmony_ci		return 0;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	pos = buf;
135662306a36Sopenharmony_ci	totlen = 0;
135762306a36Sopenharmony_ci	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
135862306a36Sopenharmony_ci		len = svc_one_xprt_name(xprt, pos, buflen - totlen);
135962306a36Sopenharmony_ci		if (len < 0) {
136062306a36Sopenharmony_ci			*buf = '\0';
136162306a36Sopenharmony_ci			totlen = len;
136262306a36Sopenharmony_ci		}
136362306a36Sopenharmony_ci		if (len <= 0)
136462306a36Sopenharmony_ci			break;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci		pos += len;
136762306a36Sopenharmony_ci		totlen += len;
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
137162306a36Sopenharmony_ci	return totlen;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_xprt_names);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci/*----------------------------------------------------------------------------*/
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic void *svc_pool_stats_start(struct seq_file *m, loff_t *pos)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	unsigned int pidx = (unsigned int)*pos;
138162306a36Sopenharmony_ci	struct svc_serv *serv = m->private;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	dprintk("svc_pool_stats_start, *pidx=%u\n", pidx);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (!pidx)
138662306a36Sopenharmony_ci		return SEQ_START_TOKEN;
138762306a36Sopenharmony_ci	return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]);
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	struct svc_pool *pool = p;
139362306a36Sopenharmony_ci	struct svc_serv *serv = m->private;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	dprintk("svc_pool_stats_next, *pos=%llu\n", *pos);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (p == SEQ_START_TOKEN) {
139862306a36Sopenharmony_ci		pool = &serv->sv_pools[0];
139962306a36Sopenharmony_ci	} else {
140062306a36Sopenharmony_ci		unsigned int pidx = (pool - &serv->sv_pools[0]);
140162306a36Sopenharmony_ci		if (pidx < serv->sv_nrpools-1)
140262306a36Sopenharmony_ci			pool = &serv->sv_pools[pidx+1];
140362306a36Sopenharmony_ci		else
140462306a36Sopenharmony_ci			pool = NULL;
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci	++*pos;
140762306a36Sopenharmony_ci	return pool;
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic void svc_pool_stats_stop(struct seq_file *m, void *p)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cistatic int svc_pool_stats_show(struct seq_file *m, void *p)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	struct svc_pool *pool = p;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	if (p == SEQ_START_TOKEN) {
141962306a36Sopenharmony_ci		seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken threads-timedout\n");
142062306a36Sopenharmony_ci		return 0;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	seq_printf(m, "%u %llu %llu %llu 0\n",
142462306a36Sopenharmony_ci		   pool->sp_id,
142562306a36Sopenharmony_ci		   percpu_counter_sum_positive(&pool->sp_messages_arrived),
142662306a36Sopenharmony_ci		   percpu_counter_sum_positive(&pool->sp_sockets_queued),
142762306a36Sopenharmony_ci		   percpu_counter_sum_positive(&pool->sp_threads_woken));
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	return 0;
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_cistatic const struct seq_operations svc_pool_stats_seq_ops = {
143362306a36Sopenharmony_ci	.start	= svc_pool_stats_start,
143462306a36Sopenharmony_ci	.next	= svc_pool_stats_next,
143562306a36Sopenharmony_ci	.stop	= svc_pool_stats_stop,
143662306a36Sopenharmony_ci	.show	= svc_pool_stats_show,
143762306a36Sopenharmony_ci};
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ciint svc_pool_stats_open(struct svc_serv *serv, struct file *file)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	int err;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	err = seq_open(file, &svc_pool_stats_seq_ops);
144462306a36Sopenharmony_ci	if (!err)
144562306a36Sopenharmony_ci		((struct seq_file *) file->private_data)->private = serv;
144662306a36Sopenharmony_ci	return err;
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ciEXPORT_SYMBOL(svc_pool_stats_open);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci/*----------------------------------------------------------------------------*/
1451