11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/net/sunrpc/svc.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * High-level RPC service routines
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks *
8bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Multiple threads pools and NUMAisation
9bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Copyright (c) 2006 Silicon Graphics, Inc.
10bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * by Greg Banks <gnb@melbourne.sgi.com>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/linkage.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
19a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks#include <linux/interrupt.h>
20a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks#include <linux/module.h>
219867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton#include <linux/kthread.h>
225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/types.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/xdr.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/stats.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/svcsock.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/clnt.h>
294d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga#include <linux/sunrpc/bc_xprt.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RPCDBG_FACILITY	RPCDBG_SVCDSP
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
335247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic void svc_unregister(const struct svc_serv *serv, struct net *net);
347252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever
3542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks#define svc_serv_is_pooled(serv)    ((serv)->sv_function)
3642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
38bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Mode for mapping cpus to pools.
39bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
40bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksenum {
4142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	SVC_POOL_AUTO = -1,	/* choose one of the others */
42bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	SVC_POOL_GLOBAL,	/* no mapping, just a single global pool
43bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks				 * (legacy & UP mode) */
44bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	SVC_POOL_PERCPU,	/* one pool per cpu */
45bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	SVC_POOL_PERNODE	/* one pool per numa node */
46bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks};
4742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks#define SVC_POOL_DEFAULT	SVC_POOL_GLOBAL
48bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
49bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
50bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Structure for mapping cpus to pools and vice versa.
51bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Setup once during sunrpc initialisation.
52bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
53bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic struct svc_pool_map {
5442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	int count;			/* How many svc_servs use us */
55bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	int mode;			/* Note: int not enum to avoid
56bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks					 * warnings about "enumeration value
57bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks					 * not handled in switch" */
58bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int npools;
59bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int *pool_to;		/* maps pool id to cpu or node */
60bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int *to_pool;		/* maps cpu or node to pool id */
61bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks} svc_pool_map = {
6242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	.count = 0,
6342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	.mode = SVC_POOL_DEFAULT
64bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks};
6542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksstatic DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */
6642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
6742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksstatic int
6842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksparam_set_pool_mode(const char *val, struct kernel_param *kp)
6942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks{
7042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	int *ip = (int *)kp->arg;
7142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	struct svc_pool_map *m = &svc_pool_map;
7242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	int err;
7342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
7442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_lock(&svc_pool_map_mutex);
7542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
7642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	err = -EBUSY;
7742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (m->count)
7842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		goto out;
7942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
8042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	err = 0;
8142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (!strncmp(val, "auto", 4))
8242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		*ip = SVC_POOL_AUTO;
8342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	else if (!strncmp(val, "global", 6))
8442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		*ip = SVC_POOL_GLOBAL;
8542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	else if (!strncmp(val, "percpu", 6))
8642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		*ip = SVC_POOL_PERCPU;
8742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	else if (!strncmp(val, "pernode", 7))
8842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		*ip = SVC_POOL_PERNODE;
8942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	else
9042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		err = -EINVAL;
9142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
9242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksout:
9342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_unlock(&svc_pool_map_mutex);
9442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	return err;
9542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks}
9642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
9742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksstatic int
9842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksparam_get_pool_mode(char *buf, struct kernel_param *kp)
9942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks{
10042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	int *ip = (int *)kp->arg;
10142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
10242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	switch (*ip)
10342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	{
10442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	case SVC_POOL_AUTO:
10542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		return strlcpy(buf, "auto", 20);
10642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	case SVC_POOL_GLOBAL:
10742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		return strlcpy(buf, "global", 20);
10842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	case SVC_POOL_PERCPU:
10942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		return strlcpy(buf, "percpu", 20);
11042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	case SVC_POOL_PERNODE:
11142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		return strlcpy(buf, "pernode", 20);
11242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	default:
11342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		return sprintf(buf, "%d", *ip);
11442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	}
11542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks}
116bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
11742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksmodule_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode,
11842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		 &svc_pool_map.mode, 0644);
119bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
120bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
121bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Detect best pool mapping mode heuristically,
122bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * according to the machine's topology.
123bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
124bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic int
125bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Bankssvc_pool_map_choose_mode(void)
126bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
127bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int node;
128bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
12962bc62a873116805774ffd37d7f86aa4faa832b1Christoph Lameter	if (nr_online_nodes > 1) {
130bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		/*
131bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * Actually have multiple NUMA nodes,
132bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * so split pools on NUMA node boundaries
133bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 */
134bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		return SVC_POOL_PERNODE;
135bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
136bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
13772c3368856c543ace033f6a5b9a3edf1f4043236H Hartley Sweeten	node = first_online_node;
138bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (nr_cpus_node(node) > 2) {
139bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		/*
140bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * Non-trivial SMP, or CONFIG_NUMA on
141bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * non-NUMA hardware, e.g. with a generic
142bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * x86_64 kernel on Xeons.  In this case we
143bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 * want to divide the pools on cpu boundaries.
144bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		 */
145bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		return SVC_POOL_PERCPU;
146bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
147bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
148bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	/* default: one global pool */
149bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return SVC_POOL_GLOBAL;
150bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
151bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
152bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
153bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Allocate the to_pool[] and pool_to[] arrays.
154bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Returns 0 on success or an errno.
155bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
156bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic int
157bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Bankssvc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
158bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
159bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
160bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (!m->to_pool)
161bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		goto fail;
162bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
163bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (!m->pool_to)
164bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		goto fail_free;
165bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
166bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return 0;
167bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
168bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksfail_free:
169bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	kfree(m->to_pool);
17061c8504c428edcebf23b97775a129c5b393a302bJ. Bruce Fields	m->to_pool = NULL;
171bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksfail:
172bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return -ENOMEM;
173bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
174bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
175bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
176bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Initialise the pool map for SVC_POOL_PERCPU mode.
177bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Returns number of pools or <0 on error.
178bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
179bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic int
180bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Bankssvc_pool_map_init_percpu(struct svc_pool_map *m)
181bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
18253b8a315b76a3f3c70a5644976c0095460eb13d8Christoph Lameter	unsigned int maxpools = nr_cpu_ids;
183bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int pidx = 0;
184bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int cpu;
185bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	int err;
186bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
187bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	err = svc_pool_map_alloc_arrays(m, maxpools);
188bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (err)
189bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		return err;
190bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
191bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	for_each_online_cpu(cpu) {
192bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		BUG_ON(pidx > maxpools);
193bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		m->to_pool[cpu] = pidx;
194bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		m->pool_to[pidx] = cpu;
195bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		pidx++;
196bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
197bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	/* cpus brought online later all get mapped to pool0, sorry */
198bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
199bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return pidx;
200bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks};
201bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
202bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
203bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
204bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Initialise the pool map for SVC_POOL_PERNODE mode.
205bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Returns number of pools or <0 on error.
206bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
207bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic int
208bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Bankssvc_pool_map_init_pernode(struct svc_pool_map *m)
209bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
21074c7aa8b8581e0ba8d6d17c623b9279aaabbb0cfChristoph Lameter	unsigned int maxpools = nr_node_ids;
211bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int pidx = 0;
212bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int node;
213bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	int err;
214bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
215bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	err = svc_pool_map_alloc_arrays(m, maxpools);
216bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (err)
217bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		return err;
218bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
219bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	for_each_node_with_cpus(node) {
220bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		/* some architectures (e.g. SN2) have cpuless nodes */
221bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		BUG_ON(pidx > maxpools);
222bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		m->to_pool[node] = pidx;
223bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		m->pool_to[pidx] = node;
224bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		pidx++;
225bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
226bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	/* nodes brought online later all get mapped to pool0, sorry */
227bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
228bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return pidx;
229bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
230bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
231bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
232bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
23342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * Add a reference to the global map of cpus to pools (and
23442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * vice versa).  Initialise the map if we're the first user.
23542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * Returns the number of pools.
236bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
237bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstatic unsigned int
23842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Bankssvc_pool_map_get(void)
239bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
240bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	struct svc_pool_map *m = &svc_pool_map;
241bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	int npools = -1;
242bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
24342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_lock(&svc_pool_map_mutex);
24442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
24542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (m->count++) {
24642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		mutex_unlock(&svc_pool_map_mutex);
247bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		return m->npools;
24842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	}
249bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
25042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (m->mode == SVC_POOL_AUTO)
25142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		m->mode = svc_pool_map_choose_mode();
252bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
253bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	switch (m->mode) {
254bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	case SVC_POOL_PERCPU:
255bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		npools = svc_pool_map_init_percpu(m);
256bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		break;
257bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	case SVC_POOL_PERNODE:
258bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		npools = svc_pool_map_init_pernode(m);
259bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		break;
260bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
261bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
262bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	if (npools < 0) {
263bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		/* default, or memory allocation failure */
264bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		npools = 1;
265bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks		m->mode = SVC_POOL_GLOBAL;
266bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
267bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	m->npools = npools;
268bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
26942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_unlock(&svc_pool_map_mutex);
270bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return m->npools;
271bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
272bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
27342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
27442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks/*
27542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * Drop a reference to the global map of cpus to pools.
27642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * When the last reference is dropped, the map data is
27742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * freed; this allows the sysadmin to change the pool
27842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * mode using the pool_mode module option without
27942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks * rebooting or re-loading sunrpc.ko.
28042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks */
28142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banksstatic void
28242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Bankssvc_pool_map_put(void)
28342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks{
28442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	struct svc_pool_map *m = &svc_pool_map;
28542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
28642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_lock(&svc_pool_map_mutex);
28742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
28842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (!--m->count) {
28942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		kfree(m->to_pool);
29061c8504c428edcebf23b97775a129c5b393a302bJ. Bruce Fields		m->to_pool = NULL;
29142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		kfree(m->pool_to);
29261c8504c428edcebf23b97775a129c5b393a302bJ. Bruce Fields		m->pool_to = NULL;
29342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		m->npools = 0;
29442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	}
29542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
29642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	mutex_unlock(&svc_pool_map_mutex);
29742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks}
29842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
29942a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
30011fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazetstatic int svc_pool_map_get_node(unsigned int pidx)
30111fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet{
30211fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	const struct svc_pool_map *m = &svc_pool_map;
30311fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet
30411fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	if (m->count) {
30511fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		if (m->mode == SVC_POOL_PERCPU)
30611fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet			return cpu_to_node(m->pool_to[pidx]);
30711fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		if (m->mode == SVC_POOL_PERNODE)
30811fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet			return m->pool_to[pidx];
30911fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	}
31011fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	return NUMA_NO_NODE;
31111fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet}
312bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
3139867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton * Set the given thread's cpus_allowed mask so that it
314bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * will only run on cpus in the given pool.
315bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
3169867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Laytonstatic inline void
3179867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Laytonsvc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
318bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
319bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	struct svc_pool_map *m = &svc_pool_map;
3209867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	unsigned int node = m->pool_to[pidx];
321bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
322bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	/*
323bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	 * The caller checks for sv_nrpools > 1, which
32442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	 * implies that we've been initialized.
325bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	 */
3261bd58aaff44485ec9e3640af350f6ba1b33e2becWeston Andros Adamson	WARN_ON_ONCE(m->count == 0);
3271bd58aaff44485ec9e3640af350f6ba1b33e2becWeston Andros Adamson	if (m->count == 0)
3281bd58aaff44485ec9e3640af350f6ba1b33e2becWeston Andros Adamson		return;
329bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
3309867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	switch (m->mode) {
331bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	case SVC_POOL_PERCPU:
332c5f59f0833df945eef7ff35f3dc6ba61c5f293ddMike Travis	{
333aa85ea5b89c36c51200d795dd788139bd9b8cf50Rusty Russell		set_cpus_allowed_ptr(task, cpumask_of(node));
3349867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		break;
335c5f59f0833df945eef7ff35f3dc6ba61c5f293ddMike Travis	}
336bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	case SVC_POOL_PERNODE:
337c5f59f0833df945eef7ff35f3dc6ba61c5f293ddMike Travis	{
338a70f730282019f487aa33a84e5ac9a5e89c5abd0Rusty Russell		set_cpus_allowed_ptr(task, cpumask_of_node(node));
3399867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		break;
340bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
341c5f59f0833df945eef7ff35f3dc6ba61c5f293ddMike Travis	}
342bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
343bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
344bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
345bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Use the mapping mode to choose a pool for a given CPU.
346bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * Used when enqueueing an incoming RPC.  Always returns
347bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks * a non-NULL pool pointer.
348bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks */
349bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banksstruct svc_pool *
350bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Bankssvc_pool_for_cpu(struct svc_serv *serv, int cpu)
351bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks{
352bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	struct svc_pool_map *m = &svc_pool_map;
353bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	unsigned int pidx = 0;
354bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
355bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	/*
35642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	 * An uninitialised map happens in a pure client when
357bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	 * lockd is brought up, so silently treat it the
358bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	 * same as SVC_POOL_GLOBAL.
359bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	 */
36042a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (svc_serv_is_pooled(serv)) {
36142a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		switch (m->mode) {
36242a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		case SVC_POOL_PERCPU:
36342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks			pidx = m->to_pool[cpu];
36442a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks			break;
36542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		case SVC_POOL_PERNODE:
36642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks			pidx = m->to_pool[cpu_to_node(cpu)];
36742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks			break;
36842a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		}
369bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	}
370bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks	return &serv->sv_pools[pidx % serv->sv_nrpools];
371bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks}
372bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
373bb2224df5ffe4f864f5b696199b17db1ce77bc0aStanislav Kinsburskyint svc_rpcb_setup(struct svc_serv *serv, struct net *net)
374d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky{
375d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	int err;
376d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
377bee42f688c915b510a4aabae4f7a99457137d6f3Stanislav Kinsbursky	err = rpcb_create_local(net);
378d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	if (err)
379d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky		return err;
380d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
381d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	/* Remove any stale portmap registrations */
382bee42f688c915b510a4aabae4f7a99457137d6f3Stanislav Kinsbursky	svc_unregister(serv, net);
383d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	return 0;
384d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky}
385bb2224df5ffe4f864f5b696199b17db1ce77bc0aStanislav KinsburskyEXPORT_SYMBOL_GPL(svc_rpcb_setup);
386d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
3875ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsburskyvoid svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
388d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky{
3895ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsbursky	svc_unregister(serv, net);
3905ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsbursky	rpcb_put_local(net);
391d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky}
39216d0587090ab93206768f726f71d84ecf55e05c4Stanislav KinsburskyEXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
393d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
394d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsburskystatic int svc_uses_rpcbind(struct svc_serv *serv)
395d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky{
396d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	struct svc_program	*progp;
397d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	unsigned int		i;
398d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
399d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
400d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky		for (i = 0; i < progp->pg_nvers; i++) {
401d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky			if (progp->pg_vers[i] == NULL)
402d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky				continue;
403d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky			if (progp->pg_vers[i]->vs_hidden == 0)
404d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky				return 1;
405d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky		}
406d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	}
407d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky
408d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky	return 0;
409d99085605cd245d8f24858e9d0b06013e13aa044Stanislav Kinsbursky}
410bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
4119793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsburskyint svc_bind(struct svc_serv *serv, struct net *net)
4129793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky{
4139793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky	if (!svc_uses_rpcbind(serv))
4149793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky		return 0;
4159793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky	return svc_rpcb_setup(serv, net);
4169793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky}
4179793f7c88937e7ac07305ab1af1a519225836823Stanislav KinsburskyEXPORT_SYMBOL_GPL(svc_bind);
4189793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky
419bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks/*
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create an RPC service
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
422a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksstatic struct svc_serv *
423a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
4245ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsbursky	     void (*shutdown)(struct svc_serv *serv, struct net *net))
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_serv	*serv;
427ea339d46b93c7b16e067a29aad1812f7a389815aChuck Lever	unsigned int vers;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int xdrsize;
4293262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	unsigned int i;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4310da974f4f303a6842516b764507e3c0a03f41e5aPanagiotis Issaris	if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4339ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher	serv->sv_name      = prog->pg_name;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_program   = prog;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_nrthreads = 1;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats     = prog->pg_stats;
437c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown	if (bufsize > RPCSVC_MAXPAYLOAD)
438c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown		bufsize = RPCSVC_MAXPAYLOAD;
439c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown	serv->sv_max_payload = bufsize? bufsize : 4096;
440c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown	serv->sv_max_mesg  = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
441bc591ccff27e6a85d3a0d6fcb16cfadcc45267a8NeilBrown	serv->sv_shutdown  = shutdown;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdrsize = 0;
4439ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher	while (prog) {
4449ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher		prog->pg_lovers = prog->pg_nvers-1;
4459ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher		for (vers=0; vers<prog->pg_nvers ; vers++)
4469ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher			if (prog->pg_vers[vers]) {
4479ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher				prog->pg_hivers = vers;
4489ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher				if (prog->pg_lovers > vers)
4499ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher					prog->pg_lovers = vers;
4509ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher				if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
4519ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher					xdrsize = prog->pg_vers[vers]->vs_xdrsize;
4529ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher			}
4539ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher		prog = prog->pg_next;
4549ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_xdrsize   = xdrsize;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&serv->sv_tempsocks);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&serv->sv_permsocks);
45836bdfc8bae51339aa27ef8e4ce148185293061aeGreg Banks	init_timer(&serv->sv_temptimer);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&serv->sv_lock);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	serv->sv_nrpools = npools;
4623262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	serv->sv_pools =
463cd86128088554d64fea1679191509f00e6353c5bRobert P. J. Day		kcalloc(serv->sv_nrpools, sizeof(struct svc_pool),
4643262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks			GFP_KERNEL);
4653262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	if (!serv->sv_pools) {
4663262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		kfree(serv);
4673262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		return NULL;
4683262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	}
4693262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
4703262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	for (i = 0; i < serv->sv_nrpools; i++) {
4713262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		struct svc_pool *pool = &serv->sv_pools[i];
4723262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
47346121cf7d85869bfe9588bac7ccf55aa0bc7f278Chuck Lever		dprintk("svc: initialising pool %u for %s\n",
4743262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks				i, serv->sv_name);
4753262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
4763262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		pool->sp_id = i;
4773262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		INIT_LIST_HEAD(&pool->sp_threads);
4783262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		INIT_LIST_HEAD(&pool->sp_sockets);
479a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		INIT_LIST_HEAD(&pool->sp_all_threads);
4803262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks		spin_lock_init(&pool->sp_lock);
4813262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	}
4823262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
4839793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky	if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown))
4849793f7c88937e7ac07305ab1af1a519225836823Stanislav Kinsbursky		serv->sv_shutdown = svc_rpcb_cleanup;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return serv;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
489a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksstruct svc_serv *
490a74554429eada89a7ddb47317e6a2968d03e41a2Greg Bankssvc_create(struct svc_program *prog, unsigned int bufsize,
4915ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsbursky	   void (*shutdown)(struct svc_serv *serv, struct net *net))
492a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks{
49349a9072f29a1039f142ec98b44a72d7173651c02Chuck Lever	return __svc_create(prog, bufsize, /*npools*/1, shutdown);
494a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks}
49524c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_create);
496a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
497a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksstruct svc_serv *
498a74554429eada89a7ddb47317e6a2968d03e41a2Greg Bankssvc_create_pooled(struct svc_program *prog, unsigned int bufsize,
4995ecebb7c7fd737cf387a552994df319c063973dbStanislav Kinsbursky		  void (*shutdown)(struct svc_serv *serv, struct net *net),
500a75c5d01e4235a7dd785548ac756f248b1b40107Jeff Layton		  svc_thread_fn func, struct module *mod)
501a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks{
502a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	struct svc_serv *serv;
50342a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	unsigned int npools = svc_pool_map_get();
504a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
50549a9072f29a1039f142ec98b44a72d7173651c02Chuck Lever	serv = __svc_create(prog, bufsize, npools, shutdown);
506a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
507a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	if (serv != NULL) {
508a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		serv->sv_function = func;
509a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		serv->sv_module = mod;
510a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	}
511a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
512a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	return serv;
513a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks}
51424c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_create_pooled);
515a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
516074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsburskyvoid svc_shutdown_net(struct svc_serv *serv, struct net *net)
517074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky{
518074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky	svc_close_net(serv, net);
519074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky
520074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky	if (serv->sv_shutdown)
521074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky		serv->sv_shutdown(serv, net);
522074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky}
523074d0f67cfe0af4927ce49560f403096b490c47fStanislav KinsburskyEXPORT_SYMBOL_GPL(svc_shutdown_net);
524074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
526bedbdd8bada194a690d2901801bf8451965086b3Neil Brown * Destroy an RPC service. Should be called with appropriate locking to
527bedbdd8bada194a690d2901801bf8451965086b3Neil Brown * protect the sv_nrthreads, sv_permsocks and sv_tempsocks.
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_destroy(struct svc_serv *serv)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
53246121cf7d85869bfe9588bac7ccf55aa0bc7f278Chuck Lever	dprintk("svc: svc_destroy(%s, %d)\n",
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				serv->sv_program->pg_name,
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				serv->sv_nrthreads);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serv->sv_nrthreads) {
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (--(serv->sv_nrthreads) != 0) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			svc_sock_update_bufs(serv);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("svc_destroy: no threads for serv=%p!\n", serv);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54436bdfc8bae51339aa27ef8e4ce148185293061aeGreg Banks	del_timer_sync(&serv->sv_temptimer);
545074d0f67cfe0af4927ce49560f403096b490c47fStanislav Kinsbursky
5467b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	/*
5477b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	 * The last user is gone and thus all sockets have to be destroyed to
5487b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	 * the point. Check this.
5497b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	 */
5507b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	BUG_ON(!list_empty(&serv->sv_permsocks));
5517b147f1ff267d12e0d189ca3d4156ed5a76b8d99Stanislav Kinsbursky	BUG_ON(!list_empty(&serv->sv_tempsocks));
552cda1fd4abd773216a888487af0170d0cc3d50454NeilBrown
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cache_clean_deferred(serv);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55542a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks	if (svc_serv_is_pooled(serv))
55642a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks		svc_pool_map_put();
55742a7fc4a6598221f1a547a76cdd45a8ab4d90e93Greg Banks
5583262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	kfree(serv->sv_pools);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(serv);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
56124c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_destroy);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate an RPC server's buffer space.
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We allocate pages and place them in rq_argpages.
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
56811fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazetsvc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5700dc220f0815497858db539d27947f3ec83202aceChuck Lever	unsigned int pages, arghi;
571cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki
572ba17686f62db88f6a591121e768a0c83a2a2647dAndy Adamson	/* bc_xprt uses fore channel allocated buffers */
573ba17686f62db88f6a591121e768a0c83a2a2647dAndy Adamson	if (svc_is_backchannel(rqstp))
574ba17686f62db88f6a591121e768a0c83a2a2647dAndy Adamson		return 1;
575ba17686f62db88f6a591121e768a0c83a2a2647dAndy Adamson
576c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
577c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown				       * We assume one is at most one page
578c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown				       */
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arghi = 0;
580b25cd058f25ea2054351bbe501956002cd8ed4c5Weston Andros Adamson	WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
581b25cd058f25ea2054351bbe501956002cd8ed4c5Weston Andros Adamson	if (pages > RPCSVC_MAXPAGES)
582b25cd058f25ea2054351bbe501956002cd8ed4c5Weston Andros Adamson		pages = RPCSVC_MAXPAGES;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (pages) {
58411fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		struct page *p = alloc_pages_node(node, GFP_KERNEL, 0);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!p)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5874452435948424e5322c2a2fefbdc2cf3732cc45dNeilBrown		rqstp->rq_pages[arghi++] = p;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pages--;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5900dc220f0815497858db539d27947f3ec83202aceChuck Lever	return pages == 0;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release an RPC server buffer
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_release_buffer(struct svc_rqst *rqstp)
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
59950c8bb13eaaf345caf2e7966667ba1d3e4d68af2Chuck Lever	unsigned int i;
60050c8bb13eaaf345caf2e7966667ba1d3e4d68af2Chuck Lever
60150c8bb13eaaf345caf2e7966667ba1d3e4d68af2Chuck Lever	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
6024452435948424e5322c2a2fefbdc2cf3732cc45dNeilBrown		if (rqstp->rq_pages[i])
6034452435948424e5322c2a2fefbdc2cf3732cc45dNeilBrown			put_page(rqstp->rq_pages[i]);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6060113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Laytonstruct svc_rqst *
60711fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazetsvc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_rqst	*rqstp;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61111fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rqstp)
6130113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton		goto out_enomem;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_nrthreads++;
6163262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	spin_lock_bh(&pool->sp_lock);
6173262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	pool->sp_nrthreads++;
618a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	list_add(&rqstp->rq_all, &pool->sp_all_threads);
6193262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	spin_unlock_bh(&pool->sp_lock);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_server = serv;
6213262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	rqstp->rq_pool = pool;
622bfd241600a3b0db4fe43c859f1460d0a958d924aGreg Banks
62311fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
6240113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton	if (!rqstp->rq_argp)
6250113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton		goto out_thread;
6260113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton
62711fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
6280113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton	if (!rqstp->rq_resp)
6290113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton		goto out_thread;
6300113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton
63111fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
6320113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton		goto out_thread;
6330113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton
6340113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton	return rqstp;
6350113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Laytonout_thread:
6360113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton	svc_exit_thread(rqstp);
6370113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Laytonout_enomem:
6380113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton	return ERR_PTR(-ENOMEM);
6390113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton}
64024c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_prepare_thread);
6410113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton
6420113ab34644649aceaac37ef4b7e5c7d5c183be3Jeff Layton/*
643a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * Choose a pool in which to create a new thread, for svc_set_num_threads
644a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks */
645a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksstatic inline struct svc_pool *
646a74554429eada89a7ddb47317e6a2968d03e41a2Greg Bankschoose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
647a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks{
648a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	if (pool != NULL)
649a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		return pool;
650a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
651cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki	return &serv->sv_pools[(*state)++ % serv->sv_nrpools];
652a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks}
653a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
654a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks/*
655a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * Choose a thread to kill, for svc_set_num_threads
656a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks */
657a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksstatic inline struct task_struct *
658a74554429eada89a7ddb47317e6a2968d03e41a2Greg Bankschoose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
659a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks{
660a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	unsigned int i;
661a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	struct task_struct *task = NULL;
662a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
663a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	if (pool != NULL) {
664a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		spin_lock_bh(&pool->sp_lock);
665a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	} else {
666a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		/* choose a pool in round-robin fashion */
667cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki		for (i = 0; i < serv->sv_nrpools; i++) {
668cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki			pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
669a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks			spin_lock_bh(&pool->sp_lock);
670cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki			if (!list_empty(&pool->sp_all_threads))
671cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki				goto found_pool;
672a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks			spin_unlock_bh(&pool->sp_lock);
673cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki		}
674a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		return NULL;
675a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	}
676a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
677a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksfound_pool:
678a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	if (!list_empty(&pool->sp_all_threads)) {
679a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		struct svc_rqst *rqstp;
680a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
681a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		/*
682a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		 * Remove from the pool->sp_all_threads list
683a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		 * so we don't try to kill it again.
684a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		 */
685a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
686a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		list_del_init(&rqstp->rq_all);
687a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		task = rqstp->rq_task;
688cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki	}
689a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	spin_unlock_bh(&pool->sp_lock);
690a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
691a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	return task;
692a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks}
693a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
694a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks/*
695a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * Create or destroy enough new threads to make the number
696a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * of threads the given number.  If `pool' is non-NULL, applies
697a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * only to threads in that pool, otherwise round-robins between
69894cf3179ccfc69d727dd884fd0831d82ada6bb06J. Bruce Fields * all pools.  Caller must ensure that mutual exclusion between this and
69994cf3179ccfc69d727dd884fd0831d82ada6bb06J. Bruce Fields * server startup or shutdown.
700a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks *
701a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * Destroying threads relies on the service threads filling in
702a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * rqstp->rq_task, which only the nfs ones do.  Assumes the serv
703a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * has been created using svc_create_pooled().
704a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks *
705a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * Based on code that used to be in nfsd_svc() but tweaked
706a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks * to be pool-aware.
707a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks */
708a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banksint
709a74554429eada89a7ddb47317e6a2968d03e41a2Greg Bankssvc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
710a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks{
7119867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	struct svc_rqst	*rqstp;
7129867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	struct task_struct *task;
7139867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	struct svc_pool *chosen_pool;
714a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	int error = 0;
715a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	unsigned int state = serv->sv_nrthreads-1;
71611fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet	int node;
717a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
718a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	if (pool == NULL) {
719a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		/* The -1 assumes caller has done a svc_get() */
720a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		nrservs -= (serv->sv_nrthreads-1);
721a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	} else {
722a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		spin_lock_bh(&pool->sp_lock);
723a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		nrservs -= pool->sp_nrthreads;
724a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		spin_unlock_bh(&pool->sp_lock);
725a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	}
726a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
727a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	/* create new threads */
728a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	while (nrservs > 0) {
729a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		nrservs--;
7309867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		chosen_pool = choose_pool(serv, pool, &state);
7319867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton
73211fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		node = svc_pool_map_get_node(chosen_pool->sp_id);
73311fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		rqstp = svc_prepare_thread(serv, chosen_pool, node);
7349867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		if (IS_ERR(rqstp)) {
7359867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton			error = PTR_ERR(rqstp);
7369867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton			break;
7379867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		}
7389867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton
739a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		__module_get(serv->sv_module);
74011fd165c68b73434ca1273e21f21db5eecc90926Eric Dumazet		task = kthread_create_on_node(serv->sv_function, rqstp,
741f170168b9a0b61ea1e647b082b38f605f1d3de3eKees Cook					      node, "%s", serv->sv_name);
7429867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		if (IS_ERR(task)) {
7439867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton			error = PTR_ERR(task);
744a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks			module_put(serv->sv_module);
7459867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton			svc_exit_thread(rqstp);
746a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks			break;
747a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		}
7489867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton
7499867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		rqstp->rq_task = task;
7509867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		if (serv->sv_nrpools > 1)
7519867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton			svc_pool_map_set_cpumask(task, chosen_pool->sp_id);
7529867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton
7539867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		svc_sock_update_bufs(serv);
7549867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton		wake_up_process(task);
755a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	}
756a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	/* destroy old threads */
757a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	while (nrservs < 0 &&
7589867d76ca16b3f455f9ca83861f4ce5c94a25928Jeff Layton	       (task = choose_victim(serv, pool, &state)) != NULL) {
759a75c5d01e4235a7dd785548ac756f248b1b40107Jeff Layton		send_sig(SIGINT, task, 1);
760a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks		nrservs++;
761a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	}
762a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
763a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	return error;
764a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks}
76524c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_set_num_threads);
766a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks
767a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks/*
768bedbdd8bada194a690d2901801bf8451965086b3Neil Brown * Called from a server thread as it's exiting. Caller must hold the BKL or
769bedbdd8bada194a690d2901801bf8451965086b3Neil Brown * the "service mutex", whichever is appropriate for the service.
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_exit_thread(struct svc_rqst *rqstp)
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_serv	*serv = rqstp->rq_server;
7753262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	struct svc_pool	*pool = rqstp->rq_pool;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	svc_release_buffer(rqstp);
778a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl	kfree(rqstp->rq_resp);
779a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl	kfree(rqstp->rq_argp);
780a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl	kfree(rqstp->rq_auth_data);
7813262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
7823262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	spin_lock_bh(&pool->sp_lock);
7833262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	pool->sp_nrthreads--;
784a74554429eada89a7ddb47317e6a2968d03e41a2Greg Banks	list_del(&rqstp->rq_all);
7853262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks	spin_unlock_bh(&pool->sp_lock);
7863262c816a3d7fb1eaabce633caa317887ed549aeGreg Banks
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(rqstp);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Release the server */
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serv)
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		svc_destroy(serv);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
79324c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_exit_thread);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7962c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Register an "inet" protocol family netid with the local
7972c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * rpcbind daemon via an rpcbind v4 SET request.
798a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever *
7992c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * No netconfig infrastructure is available in the kernel, so
8002c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * we map IP_ protocol numbers to netids by hand.
801a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever *
8022c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Returns zero on success; a negative errno value is returned
8032c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * if any error occurs.
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8055247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic int __svc_rpcb_register4(struct net *net, const u32 program,
8065247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky				const u32 version,
8072c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever				const unsigned short protocol,
8082c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever				const unsigned short port)
809a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever{
810cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	const struct sockaddr_in sin = {
811a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin_family		= AF_INET,
812a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin_addr.s_addr	= htonl(INADDR_ANY),
813a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin_port		= htons(port),
814a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever	};
815cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	const char *netid;
816cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	int error;
8172c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
8182c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	switch (protocol) {
8192c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	case IPPROTO_UDP:
8202c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever		netid = RPCBIND_NETID_UDP;
8212c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever		break;
8222c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	case IPPROTO_TCP:
8232c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever		netid = RPCBIND_NETID_TCP;
8242c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever		break;
8252c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	default:
826ba5c35e0c7e30b095636cd58b0854fdbd3c32947Chuck Lever		return -ENOPROTOOPT;
8272c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	}
8282c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
8295247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky	error = rpcb_v4_register(net, program, version,
830cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever					(const struct sockaddr *)&sin, netid);
831cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever
832cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	/*
833cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 * User space didn't support rpcbind v4, so retry this
834cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 * registration request with the legacy rpcbind v2 protocol.
835cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 */
836cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	if (error == -EPROTONOSUPPORT)
8375247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		error = rpcb_register(net, program, version, protocol, port);
838cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever
839cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	return error;
8402c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever}
8412c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
842dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6)
8432c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever/*
8442c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Register an "inet6" protocol family netid with the local
8452c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * rpcbind daemon via an rpcbind v4 SET request.
8462c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever *
8472c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * No netconfig infrastructure is available in the kernel, so
8482c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * we map IP_ protocol numbers to netids by hand.
8492c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever *
8502c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Returns zero on success; a negative errno value is returned
8512c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * if any error occurs.
8522c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever */
8535247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic int __svc_rpcb_register6(struct net *net, const u32 program,
8545247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky				const u32 version,
8552c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever				const unsigned short protocol,
8562c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever				const unsigned short port)
8572c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever{
858cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	const struct sockaddr_in6 sin6 = {
859a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin6_family		= AF_INET6,
860a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin6_addr		= IN6ADDR_ANY_INIT,
861a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		.sin6_port		= htons(port),
862a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever	};
863cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	const char *netid;
864cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	int error;
865a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever
8662c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	switch (protocol) {
8672c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	case IPPROTO_UDP:
8682c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever		netid = RPCBIND_NETID_UDP6;
869a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		break;
8702c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	case IPPROTO_TCP:
871a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		netid = RPCBIND_NETID_TCP6;
872a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever		break;
873a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever	default:
874ba5c35e0c7e30b095636cd58b0854fdbd3c32947Chuck Lever		return -ENOPROTOOPT;
8752c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	}
8762c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
8775247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky	error = rpcb_v4_register(net, program, version,
878cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever					(const struct sockaddr *)&sin6, netid);
879cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever
880cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	/*
881cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 * User space didn't support rpcbind version 4, so we won't
882cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 * use a PF_INET6 listener.
883cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	 */
884cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	if (error == -EPROTONOSUPPORT)
885cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever		error = -EAFNOSUPPORT;
886cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever
887cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever	return error;
8882c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever}
889dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#endif	/* IS_ENABLED(CONFIG_IPV6) */
8902c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
8912c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever/*
8922c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Register a kernel RPC service via rpcbind version 4.
8932c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever *
8942c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * Returns zero on success; a negative errno value is returned
8952c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever * if any error occurs.
8962c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever */
8975247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic int __svc_register(struct net *net, const char *progname,
898363f724cdd3d2ae554e261be995abdeb15f7bdd9Chuck Lever			  const u32 program, const u32 version,
8994b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever			  const int family,
9002c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever			  const unsigned short protocol,
9012c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever			  const unsigned short port)
9022c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever{
903363f724cdd3d2ae554e261be995abdeb15f7bdd9Chuck Lever	int error = -EAFNOSUPPORT;
9042c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
9052c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever	switch (family) {
9064b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever	case PF_INET:
9075247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		error = __svc_rpcb_register4(net, program, version,
9082c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever						protocol, port);
909cadc0fa534e51e20fdffe1623913c163a18d71b1Chuck Lever		break;
910dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6)
9114b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever	case PF_INET6:
9125247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		error = __svc_rpcb_register6(net, program, version,
9132c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever						protocol, port);
914dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#endif
915a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever	}
916a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever
917363f724cdd3d2ae554e261be995abdeb15f7bdd9Chuck Lever	return error;
918a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever}
9192c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever
920a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever/**
921a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever * svc_register - register an RPC service with the local portmapper
922a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever * @serv: svc_serv struct for the service to register
9235247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky * @net: net namespace for the service to register
9244b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever * @family: protocol family of service's listener socket
925a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever * @proto: transport protocol number to advertise
926a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever * @port: port to advertise
927a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever *
9284b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever * Service is registered for any address in the passed-in protocol family
929a26cfad6e0a308a2c68df1f1ef50aabd48b17e6dChuck Lever */
9305247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskyint svc_register(const struct svc_serv *serv, struct net *net,
9315247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		 const int family, const unsigned short proto,
9325247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		 const unsigned short port)
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_program	*progp;
9357e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee	struct svc_version	*vers;
936ea339d46b93c7b16e067a29aad1812f7a389815aChuck Lever	unsigned int		i;
93714aeb2118d6e9fd9ee988324c740a00c80979093Chuck Lever	int			error = 0;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9390af39507f60ee9f98b20f24af09c1a60655417acWeston Andros Adamson	WARN_ON_ONCE(proto == 0 && port == 0);
9400af39507f60ee9f98b20f24af09c1a60655417acWeston Andros Adamson	if (proto == 0 && port == 0)
9410af39507f60ee9f98b20f24af09c1a60655417acWeston Andros Adamson		return -EINVAL;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
943bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
944bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch		for (i = 0; i < progp->pg_nvers; i++) {
9457e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			vers = progp->pg_vers[i];
9467e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			if (vers == NULL)
947bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch				continue;
948bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch
9492c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever			dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
950bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch					progp->pg_name,
9512c7eb0b206b8408d92c518033a359f4374c75314Chuck Lever					i,
952bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch					proto == IPPROTO_UDP?  "udp" : "tcp",
953bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch					port,
9544b62e58cccff9c5e7ffc7023f7ec24c75fbd549bChuck Lever					family,
9557e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee					vers->vs_hidden ?
9567e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee					" (but not telling portmap)" : "");
957bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch
9587e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			if (vers->vs_hidden)
959bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch				continue;
960bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch
9615247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky			error = __svc_register(net, progp->pg_name, progp->pg_prog,
962363f724cdd3d2ae554e261be995abdeb15f7bdd9Chuck Lever						i, family, proto, port);
9637e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee
9647e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			if (vers->vs_rpcb_optnl) {
9657e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee				error = 0;
9667e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee				continue;
9677e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			}
9687e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee
9697e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			if (error < 0) {
9707e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee				printk(KERN_WARNING "svc: failed to register "
9717e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee					"%sv%u RPC service (errno %d).\n",
9727e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee					progp->pg_name, i, -error);
973bc5fea4299b8bda5f73c6f79dc35d388caf8bcedOlaf Kirch				break;
9747e55b59b2f32afc83452ae250dfd6173c9a7b515Kinglong Mee			}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9787252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	return error;
9797252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever}
9807252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever
981d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever/*
982d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever * If user space is running rpcbind, it should take the v4 UNSET
983d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever * and clear everything for this [program, version].  If user space
984d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever * is running portmap, it will reject the v4 UNSET, but won't have
985d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
986d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever * in this case to clear all existing entries for [program, version].
987d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever */
9885247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic void __svc_unregister(struct net *net, const u32 program, const u32 version,
989f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever			     const char *progname)
990f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever{
991f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever	int error;
992f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever
9935247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky	error = rpcb_v4_register(net, program, version, NULL, "");
994f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever
995d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever	/*
996d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever	 * User space didn't support rpcbind v4, so retry this
997d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever	 * request with the legacy rpcbind v2 protocol.
998d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever	 */
999d5a8620f7c8a5bcade730e2fa1224191f289fb00Chuck Lever	if (error == -EPROTONOSUPPORT)
10005247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky		error = rpcb_register(net, program, version, 0, 0);
1001f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever
1002f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever	dprintk("svc: %s(%sv%u), error %d\n",
1003f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever			__func__, progname, version, error);
1004f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever}
1005f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever
10067252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever/*
1007f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever * All netids, bind addresses and ports registered for [program, version]
1008f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever * are removed from the local rpcbind database (if the service is not
1009f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever * hidden) to make way for a new instance of the service.
10107252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever *
1011f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever * The result of unregistration is reported via dprintk for those who want
1012f6fb3f6f591b50fa4f51962ad06ee0d8782e1bc8Chuck Lever * verification of the result, but is otherwise not important.
10137252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever */
10145247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsburskystatic void svc_unregister(const struct svc_serv *serv, struct net *net)
10157252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever{
10167252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	struct svc_program *progp;
10177252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	unsigned long flags;
10187252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	unsigned int i;
10197252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever
10207252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	clear_thread_flag(TIF_SIGPENDING);
10217252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever
10227252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
10237252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever		for (i = 0; i < progp->pg_nvers; i++) {
10247252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever			if (progp->pg_vers[i] == NULL)
10257252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever				continue;
10267252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever			if (progp->pg_vers[i]->vs_hidden)
10277252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever				continue;
10287252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever
10297402ab19cdd5943c7dd4f3399afe3abda8077ef5Chuck Lever			dprintk("svc: attempting to unregister %sv%u\n",
10307402ab19cdd5943c7dd4f3399afe3abda8077ef5Chuck Lever				progp->pg_name, i);
10315247fab5c82779174d50590e0200bf532248a8a1Stanislav Kinsbursky			__svc_unregister(net, progp->pg_prog, i, progp->pg_name);
10327252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever		}
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10357252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	spin_lock_irqsave(&current->sighand->siglock, flags);
10367252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	recalc_sigpending();
10377252d575ab0e8771269a3d245c36a05ace5152bdChuck Lever	spin_unlock_irqrestore(&current->sighand->siglock, flags);
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10417032a3dd923f434132643321ad5faad128611f9eJ. Bruce Fields * dprintk the given error with the address of the client that caused it.
1042354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert */
1043624ab4644819948e9dc87c114201e98f2e52490fJ. Bruce Fields#ifdef RPC_DEBUG
1044b9075fa968a0a4347aef35e235e2995c0e57ddddJoe Perchesstatic __printf(2, 3)
1045e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perchesvoid svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
1046354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert{
1047e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches	struct va_format vaf;
1048354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	va_list args;
1049354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	char 	buf[RPC_MAX_ADDRBUFLEN];
1050354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert
1051e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches	va_start(args, fmt);
1052354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert
1053e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches	vaf.fmt = fmt;
1054e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches	vaf.va = &args;
1055354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert
10567032a3dd923f434132643321ad5faad128611f9eJ. Bruce Fields	dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf);
1057354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert
1058e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches	va_end(args);
1059354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert}
1060624ab4644819948e9dc87c114201e98f2e52490fJ. Bruce Fields#else
1061624ab4644819948e9dc87c114201e98f2e52490fJ. Bruce Fieldsstatic __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
1062624ab4644819948e9dc87c114201e98f2e52490fJ. Bruce Fields#endif
1063354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert
1064354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert/*
10651cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga * Common routine for processing the RPC request.
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10671cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiagastatic int
10681cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiagasvc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_program	*progp;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_version	*versp = NULL;	/* compiler food */
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct svc_procedure	*procp = NULL;
10736fb2b47fa16c81317ec282248e6cff521cca31c2NeilBrown	struct svc_serv		*serv = rqstp->rq_server;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kxdrproc_t		xdr;
1075d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32			*statp;
10761cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	u32			prog, vers, proc;
1077d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32			auth_stat, rpc_stat;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			auth_res;
10798f8e05c5708d7e9017c47f395f8b1498f7f52922J.Bruce Fields	__be32			*reply_statp;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpc_stat = rpc_success;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (argv->iov_len < 6*4)
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_short_len;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10865c04c46aec16b3267d8fe03af886f2d41e448cd0J. Bruce Fields	/* Will be turned off only in gss privacy case: */
1087f15a5cf912f05b572d1f9f3772fba019643f4837Kinglong Mee	rqstp->rq_splice_ok = true;
10882f425878b6a71571341dcd3f9e9d1a6f6355da9cAndy Adamson	/* Will be turned off only when NFSv4 Sessions are used */
1089f15a5cf912f05b572d1f9f3772fba019643f4837Kinglong Mee	rqstp->rq_usedeferral = true;
10909e701c610923aaeac8b38b9202a686d1cc9ee35dJ. Bruce Fields	rqstp->rq_dropme = false;
1091e831fe65b10199e1e301a7316c66d6ced133712dTom Tucker
1092e831fe65b10199e1e301a7316c66d6ced133712dTom Tucker	/* Setup reply header */
1093e831fe65b10199e1e301a7316c66d6ced133712dTom Tucker	rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	svc_putu32(resv, rqstp->rq_xid);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10977699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	vers = svc_getnl(argv);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First words of reply: */
11007699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 1);		/* REPLY */
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vers != 2)		/* RPC version number */
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad_rpc;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save position in case we later decide to reject: */
11068f8e05c5708d7e9017c47f395f8b1498f7f52922J.Bruce Fields	reply_statp = resv->iov_base + resv->iov_len;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11087699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 0);		/* ACCEPT */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11107699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	rqstp->rq_prog = prog = svc_getnl(argv);	/* program number */
11117699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	rqstp->rq_vers = vers = svc_getnl(argv);	/* version number */
11127699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	rqstp->rq_proc = proc = svc_getnl(argv);	/* procedure number */
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111480d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown	for (progp = serv->sv_program; progp; progp = progp->pg_next)
111580d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown		if (prog == progp->pg_prog)
111680d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown			break;
111780d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Decode auth data, and add verifier to reply buffer.
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We do this before anything else in order to get a decent
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * auth verifier.
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	auth_res = svc_authenticate(rqstp, &auth_stat);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Also give the program a chance to reject this call: */
112580d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown	if (auth_res == SVC_OK && progp) {
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		auth_stat = rpc_autherr_badcred;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		auth_res = progp->pg_authenticate(rqstp);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (auth_res) {
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_OK:
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_GARBAGE:
1133dd35210e1e2cb46d6dba5c97f1bc3784c4f97998Harshula Jayasuriya		goto err_garbage;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_SYSERR:
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rpc_stat = rpc_system_err;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_DENIED:
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad_auth;
11391ebede86b8abbcf8833830e18e05391758cf2f28NeilBrown	case SVC_CLOSE:
11401ebede86b8abbcf8833830e18e05391758cf2f28NeilBrown		if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
11411ebede86b8abbcf8833830e18e05391758cf2f28NeilBrown			svc_close_xprt(rqstp->rq_xprt);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_DROP:
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto dropit;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SVC_COMPLETE:
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto sendit;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
114780d188a643b0f550a2aaedf7bf4dd1abd86cfc45NeilBrown
11489ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher	if (progp == NULL)
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad_prog;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vers >= progp->pg_nvers ||
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  !(versp = progp->pg_vers[vers]))
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad_vers;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	procp = versp->vs_proc + proc;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (proc >= versp->vs_nproc || !procp->pc_func)
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_bad_proc;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_procinfo = procp;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Syntactic check complete */
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpccnt++;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Build the reply header. */
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	statp = resv->iov_base +resv->iov_len;
11657699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, RPC_SUCCESS);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Bump per-procedure stats counter */
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	procp->pc_count++;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize storage for argp and resp */
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(rqstp->rq_argp, 0, procp->pc_argsize);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(rqstp->rq_resp, 0, procp->pc_ressize);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1174cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki	/* un-reserve some of the out-queue now that we have a
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * better idea of reply size
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (procp->pc_xdrressize)
1178cd123012d99fde4759500fee611e724e4f3016e3Jeff Layton		svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call the function that processes the request. */
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!versp->vs_dispatch) {
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Decode arguments */
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xdr = procp->pc_decode;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp))
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_garbage;
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Encode reply */
11909e701c610923aaeac8b38b9202a686d1cc9ee35dJ. Bruce Fields		if (rqstp->rq_dropme) {
1191d343fce148a4eee24a907a05c4101d3268045aaeNeilBrown			if (procp->pc_release)
1192d343fce148a4eee24a907a05c4101d3268045aaeNeilBrown				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
1193d343fce148a4eee24a907a05c4101d3268045aaeNeilBrown			goto dropit;
1194d343fce148a4eee24a907a05c4101d3268045aaeNeilBrown		}
1195f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		if (*statp == rpc_success &&
1196f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		    (xdr = procp->pc_encode) &&
1197f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		    !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dprintk("svc: failed to encode reply\n");
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* serv->sv_stats->rpcsystemerr++; */
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*statp = rpc_system_err;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("svc: calling dispatcher\n");
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!versp->vs_dispatch(rqstp, statp)) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Release reply info */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (procp->pc_release)
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto dropit;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check RPC status result */
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*statp != rpc_success)
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resv->iov_len = ((void*)statp)  - resv->iov_base + 4;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Release reply info */
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (procp->pc_release)
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		procp->pc_release(rqstp, NULL, rqstp->rq_resp);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (procp->pc_encode == NULL)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto dropit;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sendit:
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (svc_authorise(rqstp))
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto dropit;
12261cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	return 1;		/* Caller can now send it */
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dropit:
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	svc_authorise(rqstp);	/* doesn't hurt to call this twice */
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("svc: svc_process dropit\n");
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_short_len:
1234354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	svc_printk(rqstp, "short len %Zd, dropping request\n",
1235354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert			argv->iov_len);
123634e9a63b4f3e169b583f6ba2e26356ecbf932fbaNeilBrown
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto dropit;			/* drop request */
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad_rpc:
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadfmt++;
12417699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 1);	/* REJECT */
12427699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 0);	/* RPC_MISMATCH */
12437699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 2);	/* Only RPCv2 supported */
12447699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 2);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad_auth:
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadauth++;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore write pointer to location of accept status: */
12518f8e05c5708d7e9017c47f395f8b1498f7f52922J.Bruce Fields	xdr_ressize_check(rqstp, reply_statp);
12527699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 1);	/* REJECT */
12537699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, 1);	/* AUTH_ERROR */
12547699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, ntohl(auth_stat));	/* status */
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad_prog:
12589ba02638e4be28dd4ff724202a640264427c62d1Andreas Gruenbacher	dprintk("svc: unknown program %d\n", prog);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadfmt++;
12607699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, RPC_PROG_UNAVAIL);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad_vers:
1264354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
126534e9a63b4f3e169b583f6ba2e26356ecbf932fbaNeilBrown		       vers, prog, progp->pg_name);
126634e9a63b4f3e169b583f6ba2e26356ecbf932fbaNeilBrown
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadfmt++;
12687699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, RPC_PROG_MISMATCH);
12697699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, progp->pg_lovers);
12707699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, progp->pg_hivers);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad_proc:
1274354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	svc_printk(rqstp, "unknown procedure (%d)\n", proc);
127534e9a63b4f3e169b583f6ba2e26356ecbf932fbaNeilBrown
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadfmt++;
12777699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, RPC_PROC_UNAVAIL);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_garbage:
1281354ecbb9dd89c21708b319da8c4ffd3dd6e6811dDr. David Alan Gilbert	svc_printk(rqstp, "failed to decode args\n");
128234e9a63b4f3e169b583f6ba2e26356ecbf932fbaNeilBrown
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpc_stat = rpc_garbage_args;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_bad:
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serv->sv_stats->rpcbadfmt++;
12867699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	svc_putnl(resv, ntohl(rpc_stat));
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto sendit;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
128924c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_process);
12907adae489fe794e3e203ff168595f635d0b845e59Greg Banks
12917adae489fe794e3e203ff168595f635d0b845e59Greg Banks/*
12921cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga * Process the RPC request.
12931cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga */
12941cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiagaint
12951cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiagasvc_process(struct svc_rqst *rqstp)
12961cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga{
12971cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	struct kvec		*argv = &rqstp->rq_arg.head[0];
12981cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	struct kvec		*resv = &rqstp->rq_res.head[0];
12991cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	struct svc_serv		*serv = rqstp->rq_server;
13001cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	u32			dir;
13011cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga
13021cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	/*
13031cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	 * Setup response xdr_buf.
13041cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	 * Initially it has just one page
13051cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	 */
1306afc59400d6c65bad66d4ad0b2daf879cbff8e23eJ. Bruce Fields	rqstp->rq_next_page = &rqstp->rq_respages[1];
13071cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	resv->iov_base = page_address(rqstp->rq_respages[0]);
13081cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	resv->iov_len = 0;
13091cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.pages = rqstp->rq_respages + 1;
13101cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.len = 0;
13111cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.page_base = 0;
13121cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.page_len = 0;
13131cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.buflen = PAGE_SIZE;
13141cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.tail[0].iov_base = NULL;
13151cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_res.tail[0].iov_len = 0;
13161cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga
13171cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	rqstp->rq_xid = svc_getu32(argv);
13181cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga
13191cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	dir  = svc_getnl(argv);
13201cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	if (dir != 0) {
13211cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga		/* direction != CALL */
13221cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga		svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
13231cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga		serv->sv_stats->rpcbadfmt++;
13241cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga		svc_drop(rqstp);
13251cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga		return 0;
13261cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga	}
13271cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga
13284b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	/* Returns 1 for send, 0 for drop */
13294b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	if (svc_process_common(rqstp, argv, resv))
13304b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		return svc_send(rqstp);
13314b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	else {
13324b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		svc_drop(rqstp);
13334b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		return 0;
13344b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	}
13351cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga}
13361cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga
13379e00abc3c20904fd6a5d888bb7023925799ec8a5Trond Myklebust#if defined(CONFIG_SUNRPC_BACKCHANNEL)
13384d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga/*
13394d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga * Process a backchannel RPC request that arrived over an existing
13404d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga * outbound connection
13414d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga */
13424d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiagaint
13434d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiagabc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
13444d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	       struct svc_rqst *rqstp)
13454d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga{
13464d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	struct kvec	*argv = &rqstp->rq_arg.head[0];
13474d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	struct kvec	*resv = &rqstp->rq_res.head[0];
13484d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13494d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	/* Build the svc_rqst used by the common processing routine */
13504a19de0f4b693139bb10b7cc3cfe1f618576ba67Andy Adamson	rqstp->rq_xprt = serv->sv_bc_xprt;
13514d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	rqstp->rq_xid = req->rq_xid;
13524d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	rqstp->rq_prot = req->rq_xprt->prot;
13534d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	rqstp->rq_server = serv;
13544d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13554d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	rqstp->rq_addrlen = sizeof(req->rq_xprt->addr);
13564d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
13574d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
13584d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
13594d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13604d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	/* reset result send buffer "put" position */
13614d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	resv->iov_len = 0;
13624d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13634d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	if (rqstp->rq_prot != IPPROTO_TCP) {
13644d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga		printk(KERN_ERR "No support for Non-TCP transports!\n");
13654d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga		BUG();
13664d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	}
13674d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13684d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	/*
13694d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	 * Skip the next two words because they've already been
13704d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	 * processed in the trasport
13714d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	 */
13724d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	svc_getu32(argv);	/* XID */
13734d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga	svc_getnl(argv);	/* CALLDIR */
13744d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13754b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	/* Returns 1 for send, 0 for drop */
13764b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	if (svc_process_common(rqstp, argv, resv)) {
13774b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		memcpy(&req->rq_snd_buf, &rqstp->rq_res,
13784b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson						sizeof(req->rq_snd_buf));
13794b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		return bc_send(req);
13804b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	} else {
1381b3b02ae5865c2dcd506322e0fc6def59a042e72fTrond Myklebust		/* drop request */
1382b3b02ae5865c2dcd506322e0fc6def59a042e72fTrond Myklebust		xprt_free_bc_request(req);
13834b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson		return 0;
13844b5b3ba16be1b195d2e1161746637acd4b9fed4fAndy Adamson	}
13854d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga}
13860d961aa934b799ca7369db582e52952cc50c656dTrond MyklebustEXPORT_SYMBOL_GPL(bc_svc_process);
13879e00abc3c20904fd6a5d888bb7023925799ec8a5Trond Myklebust#endif /* CONFIG_SUNRPC_BACKCHANNEL */
13884d6bbb6233c9cf23822a2f66f8470c9f40854b77Ricardo Labiaga
13891cad7ea6fe98dc414bd3df55275c147bd15ebf97Ricardo Labiaga/*
13907adae489fe794e3e203ff168595f635d0b845e59Greg Banks * Return (transport-specific) limit on the rpc payload.
13917adae489fe794e3e203ff168595f635d0b845e59Greg Banks */
13927adae489fe794e3e203ff168595f635d0b845e59Greg Banksu32 svc_max_payload(const struct svc_rqst *rqstp)
13937adae489fe794e3e203ff168595f635d0b845e59Greg Banks{
1394490231558e058547da4ffab6d8ce8e28771749ccTom Tucker	u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
13957adae489fe794e3e203ff168595f635d0b845e59Greg Banks
1396c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown	if (rqstp->rq_server->sv_max_payload < max)
1397c6b0a9f87b82f25fa35206ec04b5160372eabab4NeilBrown		max = rqstp->rq_server->sv_max_payload;
13987adae489fe794e3e203ff168595f635d0b845e59Greg Banks	return max;
13997adae489fe794e3e203ff168595f635d0b845e59Greg Banks}
14007adae489fe794e3e203ff168595f635d0b845e59Greg BanksEXPORT_SYMBOL_GPL(svc_max_payload);
1401