xref: /openbmc/linux/net/sunrpc/svc.c (revision 5f8b7d4b2e9604d03ae06f1a2dd5a1f34c33e533)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/net/sunrpc/svc.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * High-level RPC service routines
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8bfd24160SGreg Banks  *
9bfd24160SGreg Banks  * Multiple threads pools and NUMAisation
10bfd24160SGreg Banks  * Copyright (c) 2006 Silicon Graphics, Inc.
11bfd24160SGreg Banks  * by Greg Banks <gnb@melbourne.sgi.com>
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/linkage.h>
153f07c014SIngo Molnar #include <linux/sched/signal.h>
161da177e4SLinus Torvalds #include <linux/errno.h>
171da177e4SLinus Torvalds #include <linux/net.h>
181da177e4SLinus Torvalds #include <linux/in.h>
191da177e4SLinus Torvalds #include <linux/mm.h>
20a7455442SGreg Banks #include <linux/interrupt.h>
21a7455442SGreg Banks #include <linux/module.h>
229867d76cSJeff Layton #include <linux/kthread.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/sunrpc/types.h>
261da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h>
271da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
281da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h>
291da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
304d6bbb62SRicardo Labiaga #include <linux/sunrpc/bc_xprt.h>
311da177e4SLinus Torvalds 
32860a0d9eSJeff Layton #include <trace/events/sunrpc.h>
33860a0d9eSJeff Layton 
343a126180SChuck Lever #include "fail.h"
353a126180SChuck Lever 
361da177e4SLinus Torvalds #define RPCDBG_FACILITY	RPCDBG_SVCDSP
371da177e4SLinus Torvalds 
385247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net);
397252d575SChuck Lever 
4042a7fc4aSGreg Banks #define SVC_POOL_DEFAULT	SVC_POOL_GLOBAL
41bfd24160SGreg Banks 
42bfd24160SGreg Banks /*
43cf0e124eSNeilBrown  * Mode for mapping cpus to pools.
44cf0e124eSNeilBrown  */
45cf0e124eSNeilBrown enum {
46cf0e124eSNeilBrown 	SVC_POOL_AUTO = -1,	/* choose one of the others */
47cf0e124eSNeilBrown 	SVC_POOL_GLOBAL,	/* no mapping, just a single global pool
48cf0e124eSNeilBrown 				 * (legacy & UP mode) */
49cf0e124eSNeilBrown 	SVC_POOL_PERCPU,	/* one pool per cpu */
50cf0e124eSNeilBrown 	SVC_POOL_PERNODE	/* one pool per numa node */
51cf0e124eSNeilBrown };
52cf0e124eSNeilBrown 
53cf0e124eSNeilBrown /*
54bfd24160SGreg Banks  * Structure for mapping cpus to pools and vice versa.
55bfd24160SGreg Banks  * Setup once during sunrpc initialisation.
56bfd24160SGreg Banks  */
57cf0e124eSNeilBrown 
58cf0e124eSNeilBrown struct svc_pool_map {
59cf0e124eSNeilBrown 	int count;			/* How many svc_servs use us */
60cf0e124eSNeilBrown 	int mode;			/* Note: int not enum to avoid
61cf0e124eSNeilBrown 					 * warnings about "enumeration value
62cf0e124eSNeilBrown 					 * not handled in switch" */
63cf0e124eSNeilBrown 	unsigned int npools;
64cf0e124eSNeilBrown 	unsigned int *pool_to;		/* maps pool id to cpu or node */
65cf0e124eSNeilBrown 	unsigned int *to_pool;		/* maps cpu or node to pool id */
66cf0e124eSNeilBrown };
67cf0e124eSNeilBrown 
68cf0e124eSNeilBrown static struct svc_pool_map svc_pool_map = {
6942a7fc4aSGreg Banks 	.mode = SVC_POOL_DEFAULT
70bfd24160SGreg Banks };
71d70bc0c6SJeff Layton 
7242a7fc4aSGreg Banks static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */
73bfd24160SGreg Banks 
7442a7fc4aSGreg Banks static int
param_set_pool_mode(const char * val,const struct kernel_param * kp)75e4dca7b7SKees Cook param_set_pool_mode(const char *val, const struct kernel_param *kp)
7642a7fc4aSGreg Banks {
7742a7fc4aSGreg Banks 	int *ip = (int *)kp->arg;
7842a7fc4aSGreg Banks 	struct svc_pool_map *m = &svc_pool_map;
7942a7fc4aSGreg Banks 	int err;
8042a7fc4aSGreg Banks 
8142a7fc4aSGreg Banks 	mutex_lock(&svc_pool_map_mutex);
8242a7fc4aSGreg Banks 
8342a7fc4aSGreg Banks 	err = -EBUSY;
8442a7fc4aSGreg Banks 	if (m->count)
8542a7fc4aSGreg Banks 		goto out;
8642a7fc4aSGreg Banks 
8742a7fc4aSGreg Banks 	err = 0;
8842a7fc4aSGreg Banks 	if (!strncmp(val, "auto", 4))
8942a7fc4aSGreg Banks 		*ip = SVC_POOL_AUTO;
9042a7fc4aSGreg Banks 	else if (!strncmp(val, "global", 6))
9142a7fc4aSGreg Banks 		*ip = SVC_POOL_GLOBAL;
9242a7fc4aSGreg Banks 	else if (!strncmp(val, "percpu", 6))
9342a7fc4aSGreg Banks 		*ip = SVC_POOL_PERCPU;
9442a7fc4aSGreg Banks 	else if (!strncmp(val, "pernode", 7))
9542a7fc4aSGreg Banks 		*ip = SVC_POOL_PERNODE;
9642a7fc4aSGreg Banks 	else
9742a7fc4aSGreg Banks 		err = -EINVAL;
9842a7fc4aSGreg Banks 
9942a7fc4aSGreg Banks out:
10042a7fc4aSGreg Banks 	mutex_unlock(&svc_pool_map_mutex);
10142a7fc4aSGreg Banks 	return err;
10242a7fc4aSGreg Banks }
10342a7fc4aSGreg Banks 
10442a7fc4aSGreg Banks static int
param_get_pool_mode(char * buf,const struct kernel_param * kp)105e4dca7b7SKees Cook param_get_pool_mode(char *buf, const struct kernel_param *kp)
10642a7fc4aSGreg Banks {
10742a7fc4aSGreg Banks 	int *ip = (int *)kp->arg;
10842a7fc4aSGreg Banks 
10942a7fc4aSGreg Banks 	switch (*ip)
11042a7fc4aSGreg Banks 	{
11142a7fc4aSGreg Banks 	case SVC_POOL_AUTO:
112a9156d7eSAzeem Shaikh 		return sysfs_emit(buf, "auto\n");
11342a7fc4aSGreg Banks 	case SVC_POOL_GLOBAL:
114a9156d7eSAzeem Shaikh 		return sysfs_emit(buf, "global\n");
11542a7fc4aSGreg Banks 	case SVC_POOL_PERCPU:
116a9156d7eSAzeem Shaikh 		return sysfs_emit(buf, "percpu\n");
11742a7fc4aSGreg Banks 	case SVC_POOL_PERNODE:
118a9156d7eSAzeem Shaikh 		return sysfs_emit(buf, "pernode\n");
11942a7fc4aSGreg Banks 	default:
120a9156d7eSAzeem Shaikh 		return sysfs_emit(buf, "%d\n", *ip);
12142a7fc4aSGreg Banks 	}
12242a7fc4aSGreg Banks }
12342a7fc4aSGreg Banks 
12442a7fc4aSGreg Banks module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode,
12542a7fc4aSGreg Banks 		 &svc_pool_map.mode, 0644);
126bfd24160SGreg Banks 
127bfd24160SGreg Banks /*
128bfd24160SGreg Banks  * Detect best pool mapping mode heuristically,
129bfd24160SGreg Banks  * according to the machine's topology.
130bfd24160SGreg Banks  */
131bfd24160SGreg Banks static int
svc_pool_map_choose_mode(void)132bfd24160SGreg Banks svc_pool_map_choose_mode(void)
133bfd24160SGreg Banks {
134bfd24160SGreg Banks 	unsigned int node;
135bfd24160SGreg Banks 
13662bc62a8SChristoph Lameter 	if (nr_online_nodes > 1) {
137bfd24160SGreg Banks 		/*
138bfd24160SGreg Banks 		 * Actually have multiple NUMA nodes,
139bfd24160SGreg Banks 		 * so split pools on NUMA node boundaries
140bfd24160SGreg Banks 		 */
141bfd24160SGreg Banks 		return SVC_POOL_PERNODE;
142bfd24160SGreg Banks 	}
143bfd24160SGreg Banks 
14472c33688SH Hartley Sweeten 	node = first_online_node;
145bfd24160SGreg Banks 	if (nr_cpus_node(node) > 2) {
146bfd24160SGreg Banks 		/*
147bfd24160SGreg Banks 		 * Non-trivial SMP, or CONFIG_NUMA on
148bfd24160SGreg Banks 		 * non-NUMA hardware, e.g. with a generic
149bfd24160SGreg Banks 		 * x86_64 kernel on Xeons.  In this case we
150bfd24160SGreg Banks 		 * want to divide the pools on cpu boundaries.
151bfd24160SGreg Banks 		 */
152bfd24160SGreg Banks 		return SVC_POOL_PERCPU;
153bfd24160SGreg Banks 	}
154bfd24160SGreg Banks 
155bfd24160SGreg Banks 	/* default: one global pool */
156bfd24160SGreg Banks 	return SVC_POOL_GLOBAL;
157bfd24160SGreg Banks }
158bfd24160SGreg Banks 
159bfd24160SGreg Banks /*
160bfd24160SGreg Banks  * Allocate the to_pool[] and pool_to[] arrays.
161bfd24160SGreg Banks  * Returns 0 on success or an errno.
162bfd24160SGreg Banks  */
163bfd24160SGreg Banks static int
svc_pool_map_alloc_arrays(struct svc_pool_map * m,unsigned int maxpools)164bfd24160SGreg Banks svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
165bfd24160SGreg Banks {
166bfd24160SGreg Banks 	m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
167bfd24160SGreg Banks 	if (!m->to_pool)
168bfd24160SGreg Banks 		goto fail;
169bfd24160SGreg Banks 	m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
170bfd24160SGreg Banks 	if (!m->pool_to)
171bfd24160SGreg Banks 		goto fail_free;
172bfd24160SGreg Banks 
173bfd24160SGreg Banks 	return 0;
174bfd24160SGreg Banks 
175bfd24160SGreg Banks fail_free:
176bfd24160SGreg Banks 	kfree(m->to_pool);
17761c8504cSJ. Bruce Fields 	m->to_pool = NULL;
178bfd24160SGreg Banks fail:
179bfd24160SGreg Banks 	return -ENOMEM;
180bfd24160SGreg Banks }
181bfd24160SGreg Banks 
182bfd24160SGreg Banks /*
183bfd24160SGreg Banks  * Initialise the pool map for SVC_POOL_PERCPU mode.
184bfd24160SGreg Banks  * Returns number of pools or <0 on error.
185bfd24160SGreg Banks  */
186bfd24160SGreg Banks static int
svc_pool_map_init_percpu(struct svc_pool_map * m)187bfd24160SGreg Banks svc_pool_map_init_percpu(struct svc_pool_map *m)
188bfd24160SGreg Banks {
18953b8a315SChristoph Lameter 	unsigned int maxpools = nr_cpu_ids;
190bfd24160SGreg Banks 	unsigned int pidx = 0;
191bfd24160SGreg Banks 	unsigned int cpu;
192bfd24160SGreg Banks 	int err;
193bfd24160SGreg Banks 
194bfd24160SGreg Banks 	err = svc_pool_map_alloc_arrays(m, maxpools);
195bfd24160SGreg Banks 	if (err)
196bfd24160SGreg Banks 		return err;
197bfd24160SGreg Banks 
198bfd24160SGreg Banks 	for_each_online_cpu(cpu) {
199eb63192bSDan Carpenter 		BUG_ON(pidx >= maxpools);
200bfd24160SGreg Banks 		m->to_pool[cpu] = pidx;
201bfd24160SGreg Banks 		m->pool_to[pidx] = cpu;
202bfd24160SGreg Banks 		pidx++;
203bfd24160SGreg Banks 	}
204bfd24160SGreg Banks 	/* cpus brought online later all get mapped to pool0, sorry */
205bfd24160SGreg Banks 
206bfd24160SGreg Banks 	return pidx;
207bfd24160SGreg Banks };
208bfd24160SGreg Banks 
209bfd24160SGreg Banks 
210bfd24160SGreg Banks /*
211bfd24160SGreg Banks  * Initialise the pool map for SVC_POOL_PERNODE mode.
212bfd24160SGreg Banks  * Returns number of pools or <0 on error.
213bfd24160SGreg Banks  */
214bfd24160SGreg Banks static int
svc_pool_map_init_pernode(struct svc_pool_map * m)215bfd24160SGreg Banks svc_pool_map_init_pernode(struct svc_pool_map *m)
216bfd24160SGreg Banks {
21774c7aa8bSChristoph Lameter 	unsigned int maxpools = nr_node_ids;
218bfd24160SGreg Banks 	unsigned int pidx = 0;
219bfd24160SGreg Banks 	unsigned int node;
220bfd24160SGreg Banks 	int err;
221bfd24160SGreg Banks 
222bfd24160SGreg Banks 	err = svc_pool_map_alloc_arrays(m, maxpools);
223bfd24160SGreg Banks 	if (err)
224bfd24160SGreg Banks 		return err;
225bfd24160SGreg Banks 
226bfd24160SGreg Banks 	for_each_node_with_cpus(node) {
227bfd24160SGreg Banks 		/* some architectures (e.g. SN2) have cpuless nodes */
228bfd24160SGreg Banks 		BUG_ON(pidx > maxpools);
229bfd24160SGreg Banks 		m->to_pool[node] = pidx;
230bfd24160SGreg Banks 		m->pool_to[pidx] = node;
231bfd24160SGreg Banks 		pidx++;
232bfd24160SGreg Banks 	}
233bfd24160SGreg Banks 	/* nodes brought online later all get mapped to pool0, sorry */
234bfd24160SGreg Banks 
235bfd24160SGreg Banks 	return pidx;
236bfd24160SGreg Banks }
237bfd24160SGreg Banks 
238bfd24160SGreg Banks 
239bfd24160SGreg Banks /*
24042a7fc4aSGreg Banks  * Add a reference to the global map of cpus to pools (and
24193aa619eSNeilBrown  * vice versa) if pools are in use.
24293aa619eSNeilBrown  * Initialise the map if we're the first user.
24393aa619eSNeilBrown  * Returns the number of pools. If this is '1', no reference
24493aa619eSNeilBrown  * was taken.
245bfd24160SGreg Banks  */
246cf0e124eSNeilBrown static unsigned int
svc_pool_map_get(void)24742a7fc4aSGreg Banks svc_pool_map_get(void)
248bfd24160SGreg Banks {
249bfd24160SGreg Banks 	struct svc_pool_map *m = &svc_pool_map;
250bfd24160SGreg Banks 	int npools = -1;
251bfd24160SGreg Banks 
25242a7fc4aSGreg Banks 	mutex_lock(&svc_pool_map_mutex);
253bfd24160SGreg Banks 
25442a7fc4aSGreg Banks 	if (m->count++) {
25542a7fc4aSGreg Banks 		mutex_unlock(&svc_pool_map_mutex);
25693aa619eSNeilBrown 		WARN_ON_ONCE(m->npools <= 1);
25742a7fc4aSGreg Banks 		return m->npools;
25842a7fc4aSGreg Banks 	}
25942a7fc4aSGreg Banks 
26042a7fc4aSGreg Banks 	if (m->mode == SVC_POOL_AUTO)
261bfd24160SGreg Banks 		m->mode = svc_pool_map_choose_mode();
262bfd24160SGreg Banks 
263bfd24160SGreg Banks 	switch (m->mode) {
264bfd24160SGreg Banks 	case SVC_POOL_PERCPU:
265bfd24160SGreg Banks 		npools = svc_pool_map_init_percpu(m);
266bfd24160SGreg Banks 		break;
267bfd24160SGreg Banks 	case SVC_POOL_PERNODE:
268bfd24160SGreg Banks 		npools = svc_pool_map_init_pernode(m);
269bfd24160SGreg Banks 		break;
270bfd24160SGreg Banks 	}
271bfd24160SGreg Banks 
27293aa619eSNeilBrown 	if (npools <= 0) {
273bfd24160SGreg Banks 		/* default, or memory allocation failure */
274bfd24160SGreg Banks 		npools = 1;
275bfd24160SGreg Banks 		m->mode = SVC_POOL_GLOBAL;
276bfd24160SGreg Banks 	}
277bfd24160SGreg Banks 	m->npools = npools;
278bfd24160SGreg Banks 
27993aa619eSNeilBrown 	if (npools == 1)
28093aa619eSNeilBrown 		/* service is unpooled, so doesn't hold a reference */
28193aa619eSNeilBrown 		m->count--;
28293aa619eSNeilBrown 
28342a7fc4aSGreg Banks 	mutex_unlock(&svc_pool_map_mutex);
28493aa619eSNeilBrown 	return npools;
285bfd24160SGreg Banks }
28642a7fc4aSGreg Banks 
28742a7fc4aSGreg Banks /*
28893aa619eSNeilBrown  * Drop a reference to the global map of cpus to pools, if
28993aa619eSNeilBrown  * pools were in use, i.e. if npools > 1.
29042a7fc4aSGreg Banks  * When the last reference is dropped, the map data is
29142a7fc4aSGreg Banks  * freed; this allows the sysadmin to change the pool
29242a7fc4aSGreg Banks  * mode using the pool_mode module option without
29342a7fc4aSGreg Banks  * rebooting or re-loading sunrpc.ko.
29442a7fc4aSGreg Banks  */
295cf0e124eSNeilBrown static void
svc_pool_map_put(int npools)29693aa619eSNeilBrown svc_pool_map_put(int npools)
29742a7fc4aSGreg Banks {
29842a7fc4aSGreg Banks 	struct svc_pool_map *m = &svc_pool_map;
29942a7fc4aSGreg Banks 
30093aa619eSNeilBrown 	if (npools <= 1)
30193aa619eSNeilBrown 		return;
30242a7fc4aSGreg Banks 	mutex_lock(&svc_pool_map_mutex);
30342a7fc4aSGreg Banks 
30442a7fc4aSGreg Banks 	if (!--m->count) {
30542a7fc4aSGreg Banks 		kfree(m->to_pool);
30661c8504cSJ. Bruce Fields 		m->to_pool = NULL;
30742a7fc4aSGreg Banks 		kfree(m->pool_to);
30861c8504cSJ. Bruce Fields 		m->pool_to = NULL;
30942a7fc4aSGreg Banks 		m->npools = 0;
31042a7fc4aSGreg Banks 	}
31142a7fc4aSGreg Banks 
31242a7fc4aSGreg Banks 	mutex_unlock(&svc_pool_map_mutex);
31342a7fc4aSGreg Banks }
31442a7fc4aSGreg Banks 
svc_pool_map_get_node(unsigned int pidx)31511fd165cSEric Dumazet static int svc_pool_map_get_node(unsigned int pidx)
31611fd165cSEric Dumazet {
31711fd165cSEric Dumazet 	const struct svc_pool_map *m = &svc_pool_map;
31811fd165cSEric Dumazet 
31911fd165cSEric Dumazet 	if (m->count) {
32011fd165cSEric Dumazet 		if (m->mode == SVC_POOL_PERCPU)
32111fd165cSEric Dumazet 			return cpu_to_node(m->pool_to[pidx]);
32211fd165cSEric Dumazet 		if (m->mode == SVC_POOL_PERNODE)
32311fd165cSEric Dumazet 			return m->pool_to[pidx];
32411fd165cSEric Dumazet 	}
32511fd165cSEric Dumazet 	return NUMA_NO_NODE;
32611fd165cSEric Dumazet }
327bfd24160SGreg Banks /*
3289867d76cSJeff Layton  * Set the given thread's cpus_allowed mask so that it
329bfd24160SGreg Banks  * will only run on cpus in the given pool.
330bfd24160SGreg Banks  */
3319867d76cSJeff Layton static inline void
svc_pool_map_set_cpumask(struct task_struct * task,unsigned int pidx)3329867d76cSJeff Layton svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
333bfd24160SGreg Banks {
334bfd24160SGreg Banks 	struct svc_pool_map *m = &svc_pool_map;
3359867d76cSJeff Layton 	unsigned int node = m->pool_to[pidx];
336bfd24160SGreg Banks 
337bfd24160SGreg Banks 	/*
338bfd24160SGreg Banks 	 * The caller checks for sv_nrpools > 1, which
33942a7fc4aSGreg Banks 	 * implies that we've been initialized.
340bfd24160SGreg Banks 	 */
3411bd58aafSWeston Andros Adamson 	WARN_ON_ONCE(m->count == 0);
3421bd58aafSWeston Andros Adamson 	if (m->count == 0)
3431bd58aafSWeston Andros Adamson 		return;
344bfd24160SGreg Banks 
3459867d76cSJeff Layton 	switch (m->mode) {
346bfd24160SGreg Banks 	case SVC_POOL_PERCPU:
347c5f59f08SMike Travis 	{
348aa85ea5bSRusty Russell 		set_cpus_allowed_ptr(task, cpumask_of(node));
3499867d76cSJeff Layton 		break;
350c5f59f08SMike Travis 	}
351bfd24160SGreg Banks 	case SVC_POOL_PERNODE:
352c5f59f08SMike Travis 	{
353a70f7302SRusty Russell 		set_cpus_allowed_ptr(task, cpumask_of_node(node));
3549867d76cSJeff Layton 		break;
355bfd24160SGreg Banks 	}
356bfd24160SGreg Banks 	}
357c5f59f08SMike Travis }
358bfd24160SGreg Banks 
3592059b698SChuck Lever /**
3602059b698SChuck Lever  * svc_pool_for_cpu - Select pool to run a thread on this cpu
3612059b698SChuck Lever  * @serv: An RPC service
3622059b698SChuck Lever  *
3632059b698SChuck Lever  * Use the active CPU and the svc_pool_map's mode setting to
3642059b698SChuck Lever  * select the svc thread pool to use. Once initialized, the
3652059b698SChuck Lever  * svc_pool_map does not change.
3662059b698SChuck Lever  *
3672059b698SChuck Lever  * Return value:
3682059b698SChuck Lever  *   A pointer to an svc_pool
369bfd24160SGreg Banks  */
svc_pool_for_cpu(struct svc_serv * serv)3702059b698SChuck Lever struct svc_pool *svc_pool_for_cpu(struct svc_serv *serv)
371bfd24160SGreg Banks {
372bfd24160SGreg Banks 	struct svc_pool_map *m = &svc_pool_map;
3732059b698SChuck Lever 	int cpu = raw_smp_processor_id();
374bfd24160SGreg Banks 	unsigned int pidx = 0;
375bfd24160SGreg Banks 
37693aa619eSNeilBrown 	if (serv->sv_nrpools <= 1)
37793aa619eSNeilBrown 		return serv->sv_pools;
37893aa619eSNeilBrown 
379bfd24160SGreg Banks 	switch (m->mode) {
380bfd24160SGreg Banks 	case SVC_POOL_PERCPU:
381bfd24160SGreg Banks 		pidx = m->to_pool[cpu];
382bfd24160SGreg Banks 		break;
383bfd24160SGreg Banks 	case SVC_POOL_PERNODE:
384bfd24160SGreg Banks 		pidx = m->to_pool[cpu_to_node(cpu)];
385bfd24160SGreg Banks 		break;
386bfd24160SGreg Banks 	}
38793aa619eSNeilBrown 
388bfd24160SGreg Banks 	return &serv->sv_pools[pidx % serv->sv_nrpools];
389bfd24160SGreg Banks }
390bfd24160SGreg Banks 
svc_rpcb_setup(struct svc_serv * serv,struct net * net)391bb2224dfSStanislav Kinsbursky int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
392d9908560SStanislav Kinsbursky {
393d9908560SStanislav Kinsbursky 	int err;
394d9908560SStanislav Kinsbursky 
395bee42f68SStanislav Kinsbursky 	err = rpcb_create_local(net);
396d9908560SStanislav Kinsbursky 	if (err)
397d9908560SStanislav Kinsbursky 		return err;
398d9908560SStanislav Kinsbursky 
399d9908560SStanislav Kinsbursky 	/* Remove any stale portmap registrations */
400bee42f68SStanislav Kinsbursky 	svc_unregister(serv, net);
401d9908560SStanislav Kinsbursky 	return 0;
402d9908560SStanislav Kinsbursky }
403bb2224dfSStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_setup);
404d9908560SStanislav Kinsbursky 
svc_rpcb_cleanup(struct svc_serv * serv,struct net * net)4055ecebb7cSStanislav Kinsbursky void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
406d9908560SStanislav Kinsbursky {
4075ecebb7cSStanislav Kinsbursky 	svc_unregister(serv, net);
4085ecebb7cSStanislav Kinsbursky 	rpcb_put_local(net);
409d9908560SStanislav Kinsbursky }
41016d05870SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
411d9908560SStanislav Kinsbursky 
svc_uses_rpcbind(struct svc_serv * serv)412d9908560SStanislav Kinsbursky static int svc_uses_rpcbind(struct svc_serv *serv)
413d9908560SStanislav Kinsbursky {
414d9908560SStanislav Kinsbursky 	struct svc_program	*progp;
415d9908560SStanislav Kinsbursky 	unsigned int		i;
416d9908560SStanislav Kinsbursky 
417d9908560SStanislav Kinsbursky 	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
418d9908560SStanislav Kinsbursky 		for (i = 0; i < progp->pg_nvers; i++) {
419d9908560SStanislav Kinsbursky 			if (progp->pg_vers[i] == NULL)
420d9908560SStanislav Kinsbursky 				continue;
42105a45a2dSJeff Layton 			if (!progp->pg_vers[i]->vs_hidden)
422d9908560SStanislav Kinsbursky 				return 1;
423d9908560SStanislav Kinsbursky 		}
424d9908560SStanislav Kinsbursky 	}
425d9908560SStanislav Kinsbursky 
426d9908560SStanislav Kinsbursky 	return 0;
427d9908560SStanislav Kinsbursky }
428bfd24160SGreg Banks 
svc_bind(struct svc_serv * serv,struct net * net)4299793f7c8SStanislav Kinsbursky int svc_bind(struct svc_serv *serv, struct net *net)
4309793f7c8SStanislav Kinsbursky {
4319793f7c8SStanislav Kinsbursky 	if (!svc_uses_rpcbind(serv))
4329793f7c8SStanislav Kinsbursky 		return 0;
4339793f7c8SStanislav Kinsbursky 	return svc_rpcb_setup(serv, net);
4349793f7c8SStanislav Kinsbursky }
4359793f7c8SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_bind);
4369793f7c8SStanislav Kinsbursky 
437d0025268STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL)
438d0025268STrond Myklebust static void
__svc_init_bc(struct svc_serv * serv)439d0025268STrond Myklebust __svc_init_bc(struct svc_serv *serv)
440d0025268STrond Myklebust {
441d0025268STrond Myklebust 	INIT_LIST_HEAD(&serv->sv_cb_list);
442d0025268STrond Myklebust 	spin_lock_init(&serv->sv_cb_lock);
443d0025268STrond Myklebust 	init_waitqueue_head(&serv->sv_cb_waitq);
444d0025268STrond Myklebust }
445d0025268STrond Myklebust #else
446d0025268STrond Myklebust static void
__svc_init_bc(struct svc_serv * serv)447d0025268STrond Myklebust __svc_init_bc(struct svc_serv *serv)
448d0025268STrond Myklebust {
449d0025268STrond Myklebust }
450d0025268STrond Myklebust #endif
451d0025268STrond Myklebust 
452bfd24160SGreg Banks /*
4531da177e4SLinus Torvalds  * Create an RPC service
4541da177e4SLinus Torvalds  */
455a7455442SGreg Banks static struct svc_serv *
__svc_create(struct svc_program * prog,struct svc_stat * stats,unsigned int bufsize,int npools,int (* threadfn)(void * data))456465bb0f1SJosef Bacik __svc_create(struct svc_program *prog, struct svc_stat *stats,
457465bb0f1SJosef Bacik 	     unsigned int bufsize, int npools, int (*threadfn)(void *data))
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	struct svc_serv	*serv;
460ea339d46SChuck Lever 	unsigned int vers;
4611da177e4SLinus Torvalds 	unsigned int xdrsize;
4623262c816SGreg Banks 	unsigned int i;
4631da177e4SLinus Torvalds 
4640da974f4SPanagiotis Issaris 	if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
4651da177e4SLinus Torvalds 		return NULL;
4669ba02638SAndreas Gruenbacher 	serv->sv_name      = prog->pg_name;
4671da177e4SLinus Torvalds 	serv->sv_program   = prog;
468ec52361dSNeilBrown 	kref_init(&serv->sv_refcnt);
469465bb0f1SJosef Bacik 	serv->sv_stats     = stats;
470c6b0a9f8SNeilBrown 	if (bufsize > RPCSVC_MAXPAYLOAD)
471c6b0a9f8SNeilBrown 		bufsize = RPCSVC_MAXPAYLOAD;
472c6b0a9f8SNeilBrown 	serv->sv_max_payload = bufsize? bufsize : 4096;
473c6b0a9f8SNeilBrown 	serv->sv_max_mesg  = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
47437902c63SChuck Lever 	serv->sv_threadfn = threadfn;
4751da177e4SLinus Torvalds 	xdrsize = 0;
4769ba02638SAndreas Gruenbacher 	while (prog) {
4779ba02638SAndreas Gruenbacher 		prog->pg_lovers = prog->pg_nvers-1;
4781da177e4SLinus Torvalds 		for (vers=0; vers<prog->pg_nvers ; vers++)
4791da177e4SLinus Torvalds 			if (prog->pg_vers[vers]) {
4801da177e4SLinus Torvalds 				prog->pg_hivers = vers;
4811da177e4SLinus Torvalds 				if (prog->pg_lovers > vers)
4821da177e4SLinus Torvalds 					prog->pg_lovers = vers;
4831da177e4SLinus Torvalds 				if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
4841da177e4SLinus Torvalds 					xdrsize = prog->pg_vers[vers]->vs_xdrsize;
4851da177e4SLinus Torvalds 			}
4869ba02638SAndreas Gruenbacher 		prog = prog->pg_next;
4879ba02638SAndreas Gruenbacher 	}
4881da177e4SLinus Torvalds 	serv->sv_xdrsize   = xdrsize;
4891da177e4SLinus Torvalds 	INIT_LIST_HEAD(&serv->sv_tempsocks);
4901da177e4SLinus Torvalds 	INIT_LIST_HEAD(&serv->sv_permsocks);
491ff861c4dSKees Cook 	timer_setup(&serv->sv_temptimer, NULL, 0);
4921da177e4SLinus Torvalds 	spin_lock_init(&serv->sv_lock);
4931da177e4SLinus Torvalds 
494d0025268STrond Myklebust 	__svc_init_bc(serv);
495d0025268STrond Myklebust 
496a7455442SGreg Banks 	serv->sv_nrpools = npools;
4973262c816SGreg Banks 	serv->sv_pools =
498cd861280SRobert P. J. Day 		kcalloc(serv->sv_nrpools, sizeof(struct svc_pool),
4993262c816SGreg Banks 			GFP_KERNEL);
5003262c816SGreg Banks 	if (!serv->sv_pools) {
5013262c816SGreg Banks 		kfree(serv);
5023262c816SGreg Banks 		return NULL;
5033262c816SGreg Banks 	}
5043262c816SGreg Banks 
5053262c816SGreg Banks 	for (i = 0; i < serv->sv_nrpools; i++) {
5063262c816SGreg Banks 		struct svc_pool *pool = &serv->sv_pools[i];
5073262c816SGreg Banks 
50846121cf7SChuck Lever 		dprintk("svc: initialising pool %u for %s\n",
5093262c816SGreg Banks 				i, serv->sv_name);
5103262c816SGreg Banks 
5113262c816SGreg Banks 		pool->sp_id = i;
5123262c816SGreg Banks 		INIT_LIST_HEAD(&pool->sp_sockets);
513a7455442SGreg Banks 		INIT_LIST_HEAD(&pool->sp_all_threads);
5143262c816SGreg Banks 		spin_lock_init(&pool->sp_lock);
515ccf08bedSChuck Lever 
516f208e950SChuck Lever 		percpu_counter_init(&pool->sp_messages_arrived, 0, GFP_KERNEL);
517ccf08bedSChuck Lever 		percpu_counter_init(&pool->sp_sockets_queued, 0, GFP_KERNEL);
518ccf08bedSChuck Lever 		percpu_counter_init(&pool->sp_threads_woken, 0, GFP_KERNEL);
5193262c816SGreg Banks 	}
5203262c816SGreg Banks 
5211da177e4SLinus Torvalds 	return serv;
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds 
52437902c63SChuck Lever /**
52537902c63SChuck Lever  * svc_create - Create an RPC service
52637902c63SChuck Lever  * @prog: the RPC program the new service will handle
52737902c63SChuck Lever  * @bufsize: maximum message size for @prog
52837902c63SChuck Lever  * @threadfn: a function to service RPC requests for @prog
52937902c63SChuck Lever  *
53037902c63SChuck Lever  * Returns an instantiated struct svc_serv object or NULL.
53137902c63SChuck Lever  */
svc_create(struct svc_program * prog,unsigned int bufsize,int (* threadfn)(void * data))53237902c63SChuck Lever struct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize,
53337902c63SChuck Lever 			    int (*threadfn)(void *data))
534a7455442SGreg Banks {
535465bb0f1SJosef Bacik 	return __svc_create(prog, NULL, bufsize, 1, threadfn);
536a7455442SGreg Banks }
53724c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create);
538a7455442SGreg Banks 
53937902c63SChuck Lever /**
54037902c63SChuck Lever  * svc_create_pooled - Create an RPC service with pooled threads
54137902c63SChuck Lever  * @prog: the RPC program the new service will handle
542465bb0f1SJosef Bacik  * @stats: the stats struct if desired
54337902c63SChuck Lever  * @bufsize: maximum message size for @prog
54437902c63SChuck Lever  * @threadfn: a function to service RPC requests for @prog
54537902c63SChuck Lever  *
54637902c63SChuck Lever  * Returns an instantiated struct svc_serv object or NULL.
54737902c63SChuck Lever  */
svc_create_pooled(struct svc_program * prog,struct svc_stat * stats,unsigned int bufsize,int (* threadfn)(void * data))54837902c63SChuck Lever struct svc_serv *svc_create_pooled(struct svc_program *prog,
549465bb0f1SJosef Bacik 				   struct svc_stat *stats,
55037902c63SChuck Lever 				   unsigned int bufsize,
55137902c63SChuck Lever 				   int (*threadfn)(void *data))
552a7455442SGreg Banks {
553a7455442SGreg Banks 	struct svc_serv *serv;
55442a7fc4aSGreg Banks 	unsigned int npools = svc_pool_map_get();
555a7455442SGreg Banks 
556465bb0f1SJosef Bacik 	serv = __svc_create(prog, stats, bufsize, npools, threadfn);
557067f96efSJeff Layton 	if (!serv)
558067f96efSJeff Layton 		goto out_err;
559a7455442SGreg Banks 	return serv;
560067f96efSJeff Layton out_err:
56193aa619eSNeilBrown 	svc_pool_map_put(npools);
562067f96efSJeff Layton 	return NULL;
563a7455442SGreg Banks }
56424c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create_pooled);
565a7455442SGreg Banks 
5661da177e4SLinus Torvalds /*
567bedbdd8bSNeil Brown  * Destroy an RPC service. Should be called with appropriate locking to
5682a36395fSNeilBrown  * protect sv_permsocks and sv_tempsocks.
5691da177e4SLinus Torvalds  */
5701da177e4SLinus Torvalds void
svc_destroy(struct kref * ref)571ec52361dSNeilBrown svc_destroy(struct kref *ref)
5721da177e4SLinus Torvalds {
573ec52361dSNeilBrown 	struct svc_serv *serv = container_of(ref, struct svc_serv, sv_refcnt);
574ccf08bedSChuck Lever 	unsigned int i;
5751da177e4SLinus Torvalds 
576ec52361dSNeilBrown 	dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name);
577292a089dSSteven Rostedt (Google) 	timer_shutdown_sync(&serv->sv_temptimer);
578074d0f67SStanislav Kinsbursky 
5797b147f1fSStanislav Kinsbursky 	/*
580*d54afaefSChuck Lever 	 * Remaining transports at this point are not expected.
5817b147f1fSStanislav Kinsbursky 	 */
582*d54afaefSChuck Lever 	WARN_ONCE(!list_empty(&serv->sv_permsocks),
583*d54afaefSChuck Lever 		  "SVC: permsocks remain for %s\n", serv->sv_program->pg_name);
584*d54afaefSChuck Lever 	WARN_ONCE(!list_empty(&serv->sv_tempsocks),
585*d54afaefSChuck Lever 		  "SVC: tempsocks remain for %s\n", serv->sv_program->pg_name);
586cda1fd4aSNeilBrown 
5871da177e4SLinus Torvalds 	cache_clean_deferred(serv);
5881da177e4SLinus Torvalds 
58993aa619eSNeilBrown 	svc_pool_map_put(serv->sv_nrpools);
59042a7fc4aSGreg Banks 
591ccf08bedSChuck Lever 	for (i = 0; i < serv->sv_nrpools; i++) {
592ccf08bedSChuck Lever 		struct svc_pool *pool = &serv->sv_pools[i];
593ccf08bedSChuck Lever 
594f208e950SChuck Lever 		percpu_counter_destroy(&pool->sp_messages_arrived);
595ccf08bedSChuck Lever 		percpu_counter_destroy(&pool->sp_sockets_queued);
596ccf08bedSChuck Lever 		percpu_counter_destroy(&pool->sp_threads_woken);
597ccf08bedSChuck Lever 	}
5983262c816SGreg Banks 	kfree(serv->sv_pools);
5991da177e4SLinus Torvalds 	kfree(serv);
6001da177e4SLinus Torvalds }
60124c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_destroy);
6021da177e4SLinus Torvalds 
60388e4d41aSChuck Lever static bool
svc_init_buffer(struct svc_rqst * rqstp,unsigned int size,int node)60411fd165cSEric Dumazet svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
6051da177e4SLinus Torvalds {
60688e4d41aSChuck Lever 	unsigned long pages, ret;
6071da177e4SLinus Torvalds 
608ba17686fSAndy Adamson 	/* bc_xprt uses fore channel allocated buffers */
609ba17686fSAndy Adamson 	if (svc_is_backchannel(rqstp))
61088e4d41aSChuck Lever 		return true;
611ba17686fSAndy Adamson 
612c6b0a9f8SNeilBrown 	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
613c6b0a9f8SNeilBrown 				       * We assume one is at most one page
614c6b0a9f8SNeilBrown 				       */
615b25cd058SWeston Andros Adamson 	WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
616b25cd058SWeston Andros Adamson 	if (pages > RPCSVC_MAXPAGES)
617b25cd058SWeston Andros Adamson 		pages = RPCSVC_MAXPAGES;
61888e4d41aSChuck Lever 
61988e4d41aSChuck Lever 	ret = alloc_pages_bulk_array_node(GFP_KERNEL, node, pages,
62088e4d41aSChuck Lever 					  rqstp->rq_pages);
62188e4d41aSChuck Lever 	return ret == pages;
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds /*
6251da177e4SLinus Torvalds  * Release an RPC server buffer
6261da177e4SLinus Torvalds  */
6271da177e4SLinus Torvalds static void
svc_release_buffer(struct svc_rqst * rqstp)6281da177e4SLinus Torvalds svc_release_buffer(struct svc_rqst *rqstp)
6291da177e4SLinus Torvalds {
63050c8bb13SChuck Lever 	unsigned int i;
63150c8bb13SChuck Lever 
63244524359SNeilBrown 	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
63344524359SNeilBrown 		if (rqstp->rq_pages[i])
63444524359SNeilBrown 			put_page(rqstp->rq_pages[i]);
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds 
6370113ab34SJeff Layton struct svc_rqst *
svc_rqst_alloc(struct svc_serv * serv,struct svc_pool * pool,int node)6381b6dc1dfSJeff Layton svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
6390113ab34SJeff Layton {
6400113ab34SJeff Layton 	struct svc_rqst	*rqstp;
6410113ab34SJeff Layton 
64211fd165cSEric Dumazet 	rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node);
6430113ab34SJeff Layton 	if (!rqstp)
6441b6dc1dfSJeff Layton 		return rqstp;
6450113ab34SJeff Layton 
64676fa8842SMatthew Wilcox (Oracle) 	folio_batch_init(&rqstp->rq_fbatch);
6476a0cdf56SChuck Lever 
648b1691bc0SJeff Layton 	__set_bit(RQ_BUSY, &rqstp->rq_flags);
649b1691bc0SJeff Layton 	rqstp->rq_server = serv;
650b1691bc0SJeff Layton 	rqstp->rq_pool = pool;
6511b6dc1dfSJeff Layton 
6525191955dSChuck Lever 	rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0);
6535191955dSChuck Lever 	if (!rqstp->rq_scratch_page)
6545191955dSChuck Lever 		goto out_enomem;
6555191955dSChuck Lever 
6561b6dc1dfSJeff Layton 	rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
6571b6dc1dfSJeff Layton 	if (!rqstp->rq_argp)
6581b6dc1dfSJeff Layton 		goto out_enomem;
6591b6dc1dfSJeff Layton 
6601b6dc1dfSJeff Layton 	rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
6611b6dc1dfSJeff Layton 	if (!rqstp->rq_resp)
6621b6dc1dfSJeff Layton 		goto out_enomem;
6631b6dc1dfSJeff Layton 
6641b6dc1dfSJeff Layton 	if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
6651b6dc1dfSJeff Layton 		goto out_enomem;
6661b6dc1dfSJeff Layton 
6671b6dc1dfSJeff Layton 	return rqstp;
6681b6dc1dfSJeff Layton out_enomem:
6691b6dc1dfSJeff Layton 	svc_rqst_free(rqstp);
6701b6dc1dfSJeff Layton 	return NULL;
6711b6dc1dfSJeff Layton }
6721b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_alloc);
6731b6dc1dfSJeff Layton 
6746b044fbaSNeilBrown static struct svc_rqst *
svc_prepare_thread(struct svc_serv * serv,struct svc_pool * pool,int node)6751b6dc1dfSJeff Layton svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
6761b6dc1dfSJeff Layton {
6771b6dc1dfSJeff Layton 	struct svc_rqst	*rqstp;
6781b6dc1dfSJeff Layton 
6791b6dc1dfSJeff Layton 	rqstp = svc_rqst_alloc(serv, pool, node);
6801b6dc1dfSJeff Layton 	if (!rqstp)
6811b6dc1dfSJeff Layton 		return ERR_PTR(-ENOMEM);
6821b6dc1dfSJeff Layton 
683ec52361dSNeilBrown 	svc_get(serv);
6842a36395fSNeilBrown 	spin_lock_bh(&serv->sv_lock);
6852a36395fSNeilBrown 	serv->sv_nrthreads += 1;
6862a36395fSNeilBrown 	spin_unlock_bh(&serv->sv_lock);
6872a36395fSNeilBrown 
6880113ab34SJeff Layton 	spin_lock_bh(&pool->sp_lock);
6890113ab34SJeff Layton 	pool->sp_nrthreads++;
69081244386SJeff Layton 	list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads);
6910113ab34SJeff Layton 	spin_unlock_bh(&pool->sp_lock);
6920113ab34SJeff Layton 	return rqstp;
6930113ab34SJeff Layton }
6940113ab34SJeff Layton 
695850bac3aSChuck Lever /**
696850bac3aSChuck Lever  * svc_pool_wake_idle_thread - Awaken an idle thread in @pool
697850bac3aSChuck Lever  * @pool: service thread pool
698850bac3aSChuck Lever  *
699850bac3aSChuck Lever  * Can be called from soft IRQ or process context. Finding an idle
700850bac3aSChuck Lever  * service thread and marking it BUSY is atomic with respect to
701850bac3aSChuck Lever  * other calls to svc_pool_wake_idle_thread().
702850bac3aSChuck Lever  *
703850bac3aSChuck Lever  */
svc_pool_wake_idle_thread(struct svc_pool * pool)7042a455745SNeilBrown void svc_pool_wake_idle_thread(struct svc_pool *pool)
705850bac3aSChuck Lever {
706850bac3aSChuck Lever 	struct svc_rqst	*rqstp;
707850bac3aSChuck Lever 
708850bac3aSChuck Lever 	rcu_read_lock();
709850bac3aSChuck Lever 	list_for_each_entry_rcu(rqstp, &pool->sp_all_threads, rq_all) {
710850bac3aSChuck Lever 		if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags))
711850bac3aSChuck Lever 			continue;
712850bac3aSChuck Lever 
713850bac3aSChuck Lever 		WRITE_ONCE(rqstp->rq_qtime, ktime_get());
714850bac3aSChuck Lever 		wake_up_process(rqstp->rq_task);
715850bac3aSChuck Lever 		rcu_read_unlock();
716850bac3aSChuck Lever 		percpu_counter_inc(&pool->sp_threads_woken);
717850bac3aSChuck Lever 		trace_svc_wake_up(rqstp->rq_task->pid);
7182a455745SNeilBrown 		return;
719850bac3aSChuck Lever 	}
720850bac3aSChuck Lever 	rcu_read_unlock();
721850bac3aSChuck Lever 
722850bac3aSChuck Lever 	set_bit(SP_CONGESTED, &pool->sp_flags);
723850bac3aSChuck Lever }
724850bac3aSChuck Lever 
725d2f0ef1cSChuck Lever static struct svc_pool *
svc_pool_next(struct svc_serv * serv,struct svc_pool * pool,unsigned int * state)726d2f0ef1cSChuck Lever svc_pool_next(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
727a7455442SGreg Banks {
728d2f0ef1cSChuck Lever 	return pool ? pool : &serv->sv_pools[(*state)++ % serv->sv_nrpools];
729a7455442SGreg Banks }
730a7455442SGreg Banks 
731d2f0ef1cSChuck Lever static struct task_struct *
svc_pool_victim(struct svc_serv * serv,struct svc_pool * pool,unsigned int * state)732d2f0ef1cSChuck Lever svc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
733a7455442SGreg Banks {
734a7455442SGreg Banks 	unsigned int i;
735a7455442SGreg Banks 	struct task_struct *task = NULL;
736a7455442SGreg Banks 
737a7455442SGreg Banks 	if (pool != NULL) {
738a7455442SGreg Banks 		spin_lock_bh(&pool->sp_lock);
739a7455442SGreg Banks 	} else {
740a7455442SGreg Banks 		for (i = 0; i < serv->sv_nrpools; i++) {
741a7455442SGreg Banks 			pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
742a7455442SGreg Banks 			spin_lock_bh(&pool->sp_lock);
743a7455442SGreg Banks 			if (!list_empty(&pool->sp_all_threads))
744a7455442SGreg Banks 				goto found_pool;
745a7455442SGreg Banks 			spin_unlock_bh(&pool->sp_lock);
746a7455442SGreg Banks 		}
747a7455442SGreg Banks 		return NULL;
748a7455442SGreg Banks 	}
749a7455442SGreg Banks 
750a7455442SGreg Banks found_pool:
751a7455442SGreg Banks 	if (!list_empty(&pool->sp_all_threads)) {
752a7455442SGreg Banks 		struct svc_rqst *rqstp;
753a7455442SGreg Banks 
754a7455442SGreg Banks 		rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
75581244386SJeff Layton 		set_bit(RQ_VICTIM, &rqstp->rq_flags);
75681244386SJeff Layton 		list_del_rcu(&rqstp->rq_all);
757a7455442SGreg Banks 		task = rqstp->rq_task;
758a7455442SGreg Banks 	}
759a7455442SGreg Banks 	spin_unlock_bh(&pool->sp_lock);
760a7455442SGreg Banks 	return task;
761a7455442SGreg Banks }
762a7455442SGreg Banks 
7639e0d8768STrond Myklebust static int
svc_start_kthreads(struct svc_serv * serv,struct svc_pool * pool,int nrservs)7649e0d8768STrond Myklebust svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
7659e0d8768STrond Myklebust {
7669e0d8768STrond Myklebust 	struct svc_rqst	*rqstp;
7679e0d8768STrond Myklebust 	struct task_struct *task;
7689e0d8768STrond Myklebust 	struct svc_pool *chosen_pool;
7699e0d8768STrond Myklebust 	unsigned int state = serv->sv_nrthreads-1;
7709e0d8768STrond Myklebust 	int node;
7719e0d8768STrond Myklebust 
7729e0d8768STrond Myklebust 	do {
7739e0d8768STrond Myklebust 		nrservs--;
774d2f0ef1cSChuck Lever 		chosen_pool = svc_pool_next(serv, pool, &state);
7759e0d8768STrond Myklebust 		node = svc_pool_map_get_node(chosen_pool->sp_id);
776d2f0ef1cSChuck Lever 
7779e0d8768STrond Myklebust 		rqstp = svc_prepare_thread(serv, chosen_pool, node);
7789e0d8768STrond Myklebust 		if (IS_ERR(rqstp))
7799e0d8768STrond Myklebust 			return PTR_ERR(rqstp);
78037902c63SChuck Lever 		task = kthread_create_on_node(serv->sv_threadfn, rqstp,
7819e0d8768STrond Myklebust 					      node, "%s", serv->sv_name);
7829e0d8768STrond Myklebust 		if (IS_ERR(task)) {
7839e0d8768STrond Myklebust 			svc_exit_thread(rqstp);
7849e0d8768STrond Myklebust 			return PTR_ERR(task);
7859e0d8768STrond Myklebust 		}
7869e0d8768STrond Myklebust 
7879e0d8768STrond Myklebust 		rqstp->rq_task = task;
7889e0d8768STrond Myklebust 		if (serv->sv_nrpools > 1)
7899e0d8768STrond Myklebust 			svc_pool_map_set_cpumask(task, chosen_pool->sp_id);
7909e0d8768STrond Myklebust 
7919e0d8768STrond Myklebust 		svc_sock_update_bufs(serv);
7929e0d8768STrond Myklebust 		wake_up_process(task);
7939e0d8768STrond Myklebust 	} while (nrservs > 0);
7949e0d8768STrond Myklebust 
7959e0d8768STrond Myklebust 	return 0;
7969e0d8768STrond Myklebust }
7979e0d8768STrond Myklebust 
798ed6473ddSTrond Myklebust static int
svc_stop_kthreads(struct svc_serv * serv,struct svc_pool * pool,int nrservs)799ed6473ddSTrond Myklebust svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
800ed6473ddSTrond Myklebust {
8019ca6705dSBenjamin Coddington 	struct svc_rqst	*rqstp;
802ed6473ddSTrond Myklebust 	struct task_struct *task;
803ed6473ddSTrond Myklebust 	unsigned int state = serv->sv_nrthreads-1;
804ed6473ddSTrond Myklebust 
805ed6473ddSTrond Myklebust 	do {
806d2f0ef1cSChuck Lever 		task = svc_pool_victim(serv, pool, &state);
807ed6473ddSTrond Myklebust 		if (task == NULL)
808ed6473ddSTrond Myklebust 			break;
8099ca6705dSBenjamin Coddington 		rqstp = kthread_data(task);
8109ca6705dSBenjamin Coddington 		/* Did we lose a race to svo_function threadfn? */
8119ca6705dSBenjamin Coddington 		if (kthread_stop(task) == -EINTR)
8129ca6705dSBenjamin Coddington 			svc_exit_thread(rqstp);
813ed6473ddSTrond Myklebust 		nrservs++;
814ed6473ddSTrond Myklebust 	} while (nrservs < 0);
815ed6473ddSTrond Myklebust 	return 0;
816ed6473ddSTrond Myklebust }
817ed6473ddSTrond Myklebust 
818d2f0ef1cSChuck Lever /**
819d2f0ef1cSChuck Lever  * svc_set_num_threads - adjust number of threads per RPC service
820d2f0ef1cSChuck Lever  * @serv: RPC service to adjust
821d2f0ef1cSChuck Lever  * @pool: Specific pool from which to choose threads, or NULL
822d2f0ef1cSChuck Lever  * @nrservs: New number of threads for @serv (0 or less means kill all threads)
823d2f0ef1cSChuck Lever  *
824d2f0ef1cSChuck Lever  * Create or destroy threads to make the number of threads for @serv the
825d2f0ef1cSChuck Lever  * given number. If @pool is non-NULL, change only threads in that pool;
826d2f0ef1cSChuck Lever  * otherwise, round-robin between all pools for @serv. @serv's
827d2f0ef1cSChuck Lever  * sv_nrthreads is adjusted for each thread created or destroyed.
828d2f0ef1cSChuck Lever  *
829d2f0ef1cSChuck Lever  * Caller must ensure mutual exclusion between this and server startup or
830d2f0ef1cSChuck Lever  * shutdown.
831d2f0ef1cSChuck Lever  *
832d2f0ef1cSChuck Lever  * Returns zero on success or a negative errno if an error occurred while
833d2f0ef1cSChuck Lever  * starting a thread.
834d2f0ef1cSChuck Lever  */
835ed6473ddSTrond Myklebust int
svc_set_num_threads(struct svc_serv * serv,struct svc_pool * pool,int nrservs)8363ebdbe52SNeilBrown svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
837ed6473ddSTrond Myklebust {
838ed6473ddSTrond Myklebust 	if (pool == NULL) {
839ec52361dSNeilBrown 		nrservs -= serv->sv_nrthreads;
840ed6473ddSTrond Myklebust 	} else {
841ed6473ddSTrond Myklebust 		spin_lock_bh(&pool->sp_lock);
842ed6473ddSTrond Myklebust 		nrservs -= pool->sp_nrthreads;
843ed6473ddSTrond Myklebust 		spin_unlock_bh(&pool->sp_lock);
844ed6473ddSTrond Myklebust 	}
845ed6473ddSTrond Myklebust 
846ed6473ddSTrond Myklebust 	if (nrservs > 0)
847ed6473ddSTrond Myklebust 		return svc_start_kthreads(serv, pool, nrservs);
848ed6473ddSTrond Myklebust 	if (nrservs < 0)
849ed6473ddSTrond Myklebust 		return svc_stop_kthreads(serv, pool, nrservs);
850ed6473ddSTrond Myklebust 	return 0;
851ed6473ddSTrond Myklebust }
8523ebdbe52SNeilBrown EXPORT_SYMBOL_GPL(svc_set_num_threads);
853ed6473ddSTrond Myklebust 
8542f0f88f4SChuck Lever /**
8552f0f88f4SChuck Lever  * svc_rqst_replace_page - Replace one page in rq_pages[]
8562f0f88f4SChuck Lever  * @rqstp: svc_rqst with pages to replace
8572f0f88f4SChuck Lever  * @page: replacement page
8582f0f88f4SChuck Lever  *
8592f0f88f4SChuck Lever  * When replacing a page in rq_pages, batch the release of the
8602f0f88f4SChuck Lever  * replaced pages to avoid hammering the page allocator.
8610f516248SChuck Lever  *
8620f516248SChuck Lever  * Return values:
8630f516248SChuck Lever  *   %true: page replaced
8640f516248SChuck Lever  *   %false: array bounds checking failed
8652f0f88f4SChuck Lever  */
svc_rqst_replace_page(struct svc_rqst * rqstp,struct page * page)8660f516248SChuck Lever bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
8672f0f88f4SChuck Lever {
8680f516248SChuck Lever 	struct page **begin = rqstp->rq_pages;
8690f516248SChuck Lever 	struct page **end = &rqstp->rq_pages[RPCSVC_MAXPAGES];
8700f516248SChuck Lever 
8710f516248SChuck Lever 	if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) {
8720f516248SChuck Lever 		trace_svc_replace_page_err(rqstp);
8730f516248SChuck Lever 		return false;
8740f516248SChuck Lever 	}
8750f516248SChuck Lever 
8762f0f88f4SChuck Lever 	if (*rqstp->rq_next_page) {
87776fa8842SMatthew Wilcox (Oracle) 		if (!folio_batch_add(&rqstp->rq_fbatch,
87876fa8842SMatthew Wilcox (Oracle) 				page_folio(*rqstp->rq_next_page)))
87976fa8842SMatthew Wilcox (Oracle) 			__folio_batch_release(&rqstp->rq_fbatch);
8802f0f88f4SChuck Lever 	}
8812f0f88f4SChuck Lever 
8822f0f88f4SChuck Lever 	get_page(page);
8832f0f88f4SChuck Lever 	*(rqstp->rq_next_page++) = page;
8840f516248SChuck Lever 	return true;
8852f0f88f4SChuck Lever }
8862f0f88f4SChuck Lever EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
8872f0f88f4SChuck Lever 
888b20cb39dSChuck Lever /**
889b20cb39dSChuck Lever  * svc_rqst_release_pages - Release Reply buffer pages
890b20cb39dSChuck Lever  * @rqstp: RPC transaction context
891b20cb39dSChuck Lever  *
892b20cb39dSChuck Lever  * Release response pages that might still be in flight after
893b20cb39dSChuck Lever  * svc_send, and any spliced filesystem-owned pages.
894b20cb39dSChuck Lever  */
svc_rqst_release_pages(struct svc_rqst * rqstp)895b20cb39dSChuck Lever void svc_rqst_release_pages(struct svc_rqst *rqstp)
896b20cb39dSChuck Lever {
897647a2a64SChuck Lever 	int i, count = rqstp->rq_next_page - rqstp->rq_respages;
898b20cb39dSChuck Lever 
899647a2a64SChuck Lever 	if (count) {
900647a2a64SChuck Lever 		release_pages(rqstp->rq_respages, count);
901647a2a64SChuck Lever 		for (i = 0; i < count; i++)
902647a2a64SChuck Lever 			rqstp->rq_respages[i] = NULL;
903b20cb39dSChuck Lever 	}
904b20cb39dSChuck Lever }
905b20cb39dSChuck Lever 
906a7455442SGreg Banks /*
9073c519914SJeff Layton  * Called from a server thread as it's exiting. Caller must hold the "service
9083c519914SJeff Layton  * mutex" for the service.
9091da177e4SLinus Torvalds  */
9101da177e4SLinus Torvalds void
svc_rqst_free(struct svc_rqst * rqstp)9111b6dc1dfSJeff Layton svc_rqst_free(struct svc_rqst *rqstp)
9121da177e4SLinus Torvalds {
91376fa8842SMatthew Wilcox (Oracle) 	folio_batch_release(&rqstp->rq_fbatch);
9141da177e4SLinus Torvalds 	svc_release_buffer(rqstp);
915b9f83ffaSYunjian Wang 	if (rqstp->rq_scratch_page)
9165191955dSChuck Lever 		put_page(rqstp->rq_scratch_page);
9171da177e4SLinus Torvalds 	kfree(rqstp->rq_resp);
9181da177e4SLinus Torvalds 	kfree(rqstp->rq_argp);
9191da177e4SLinus Torvalds 	kfree(rqstp->rq_auth_data);
9201b6dc1dfSJeff Layton 	kfree_rcu(rqstp, rq_rcu_head);
9211b6dc1dfSJeff Layton }
9221b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_free);
9231b6dc1dfSJeff Layton 
9241b6dc1dfSJeff Layton void
svc_exit_thread(struct svc_rqst * rqstp)9251b6dc1dfSJeff Layton svc_exit_thread(struct svc_rqst *rqstp)
9261b6dc1dfSJeff Layton {
9271b6dc1dfSJeff Layton 	struct svc_serv	*serv = rqstp->rq_server;
9281b6dc1dfSJeff Layton 	struct svc_pool	*pool = rqstp->rq_pool;
9293262c816SGreg Banks 
9303262c816SGreg Banks 	spin_lock_bh(&pool->sp_lock);
9313262c816SGreg Banks 	pool->sp_nrthreads--;
93281244386SJeff Layton 	if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags))
93381244386SJeff Layton 		list_del_rcu(&rqstp->rq_all);
9343262c816SGreg Banks 	spin_unlock_bh(&pool->sp_lock);
9353262c816SGreg Banks 
9362a36395fSNeilBrown 	spin_lock_bh(&serv->sv_lock);
937ec52361dSNeilBrown 	serv->sv_nrthreads -= 1;
9382a36395fSNeilBrown 	spin_unlock_bh(&serv->sv_lock);
939ec52361dSNeilBrown 	svc_sock_update_bufs(serv);
940ec52361dSNeilBrown 
9411b6dc1dfSJeff Layton 	svc_rqst_free(rqstp);
9421da177e4SLinus Torvalds 
943ec52361dSNeilBrown 	svc_put(serv);
9441da177e4SLinus Torvalds }
94524c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_exit_thread);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds /*
9482c7eb0b2SChuck Lever  * Register an "inet" protocol family netid with the local
9492c7eb0b2SChuck Lever  * rpcbind daemon via an rpcbind v4 SET request.
950a26cfad6SChuck Lever  *
9512c7eb0b2SChuck Lever  * No netconfig infrastructure is available in the kernel, so
9522c7eb0b2SChuck Lever  * we map IP_ protocol numbers to netids by hand.
953a26cfad6SChuck Lever  *
9542c7eb0b2SChuck Lever  * Returns zero on success; a negative errno value is returned
9552c7eb0b2SChuck Lever  * if any error occurs.
9561da177e4SLinus Torvalds  */
__svc_rpcb_register4(struct net * net,const u32 program,const u32 version,const unsigned short protocol,const unsigned short port)9575247fab5SStanislav Kinsbursky static int __svc_rpcb_register4(struct net *net, const u32 program,
9585247fab5SStanislav Kinsbursky 				const u32 version,
959a26cfad6SChuck Lever 				const unsigned short protocol,
960a26cfad6SChuck Lever 				const unsigned short port)
961a26cfad6SChuck Lever {
962cadc0fa5SChuck Lever 	const struct sockaddr_in sin = {
963a26cfad6SChuck Lever 		.sin_family		= AF_INET,
964a26cfad6SChuck Lever 		.sin_addr.s_addr	= htonl(INADDR_ANY),
965a26cfad6SChuck Lever 		.sin_port		= htons(port),
966a26cfad6SChuck Lever 	};
967cadc0fa5SChuck Lever 	const char *netid;
968cadc0fa5SChuck Lever 	int error;
9692c7eb0b2SChuck Lever 
9702c7eb0b2SChuck Lever 	switch (protocol) {
9712c7eb0b2SChuck Lever 	case IPPROTO_UDP:
9722c7eb0b2SChuck Lever 		netid = RPCBIND_NETID_UDP;
9732c7eb0b2SChuck Lever 		break;
9742c7eb0b2SChuck Lever 	case IPPROTO_TCP:
9752c7eb0b2SChuck Lever 		netid = RPCBIND_NETID_TCP;
9762c7eb0b2SChuck Lever 		break;
9772c7eb0b2SChuck Lever 	default:
978ba5c35e0SChuck Lever 		return -ENOPROTOOPT;
9792c7eb0b2SChuck Lever 	}
9802c7eb0b2SChuck Lever 
9815247fab5SStanislav Kinsbursky 	error = rpcb_v4_register(net, program, version,
982cadc0fa5SChuck Lever 					(const struct sockaddr *)&sin, netid);
983cadc0fa5SChuck Lever 
984cadc0fa5SChuck Lever 	/*
985cadc0fa5SChuck Lever 	 * User space didn't support rpcbind v4, so retry this
986cadc0fa5SChuck Lever 	 * registration request with the legacy rpcbind v2 protocol.
987cadc0fa5SChuck Lever 	 */
988cadc0fa5SChuck Lever 	if (error == -EPROTONOSUPPORT)
9895247fab5SStanislav Kinsbursky 		error = rpcb_register(net, program, version, protocol, port);
990cadc0fa5SChuck Lever 
991cadc0fa5SChuck Lever 	return error;
9922c7eb0b2SChuck Lever }
9932c7eb0b2SChuck Lever 
994dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
9952c7eb0b2SChuck Lever /*
9962c7eb0b2SChuck Lever  * Register an "inet6" protocol family netid with the local
9972c7eb0b2SChuck Lever  * rpcbind daemon via an rpcbind v4 SET request.
9982c7eb0b2SChuck Lever  *
9992c7eb0b2SChuck Lever  * No netconfig infrastructure is available in the kernel, so
10002c7eb0b2SChuck Lever  * we map IP_ protocol numbers to netids by hand.
10012c7eb0b2SChuck Lever  *
10022c7eb0b2SChuck Lever  * Returns zero on success; a negative errno value is returned
10032c7eb0b2SChuck Lever  * if any error occurs.
10042c7eb0b2SChuck Lever  */
__svc_rpcb_register6(struct net * net,const u32 program,const u32 version,const unsigned short protocol,const unsigned short port)10055247fab5SStanislav Kinsbursky static int __svc_rpcb_register6(struct net *net, const u32 program,
10065247fab5SStanislav Kinsbursky 				const u32 version,
10072c7eb0b2SChuck Lever 				const unsigned short protocol,
10082c7eb0b2SChuck Lever 				const unsigned short port)
10092c7eb0b2SChuck Lever {
1010cadc0fa5SChuck Lever 	const struct sockaddr_in6 sin6 = {
1011a26cfad6SChuck Lever 		.sin6_family		= AF_INET6,
1012a26cfad6SChuck Lever 		.sin6_addr		= IN6ADDR_ANY_INIT,
1013a26cfad6SChuck Lever 		.sin6_port		= htons(port),
1014a26cfad6SChuck Lever 	};
1015cadc0fa5SChuck Lever 	const char *netid;
1016cadc0fa5SChuck Lever 	int error;
1017a26cfad6SChuck Lever 
10182c7eb0b2SChuck Lever 	switch (protocol) {
10192c7eb0b2SChuck Lever 	case IPPROTO_UDP:
10202c7eb0b2SChuck Lever 		netid = RPCBIND_NETID_UDP6;
10212c7eb0b2SChuck Lever 		break;
10222c7eb0b2SChuck Lever 	case IPPROTO_TCP:
10232c7eb0b2SChuck Lever 		netid = RPCBIND_NETID_TCP6;
10242c7eb0b2SChuck Lever 		break;
10252c7eb0b2SChuck Lever 	default:
1026ba5c35e0SChuck Lever 		return -ENOPROTOOPT;
10272c7eb0b2SChuck Lever 	}
10282c7eb0b2SChuck Lever 
10295247fab5SStanislav Kinsbursky 	error = rpcb_v4_register(net, program, version,
1030cadc0fa5SChuck Lever 					(const struct sockaddr *)&sin6, netid);
1031cadc0fa5SChuck Lever 
1032cadc0fa5SChuck Lever 	/*
1033cadc0fa5SChuck Lever 	 * User space didn't support rpcbind version 4, so we won't
1034cadc0fa5SChuck Lever 	 * use a PF_INET6 listener.
1035cadc0fa5SChuck Lever 	 */
1036cadc0fa5SChuck Lever 	if (error == -EPROTONOSUPPORT)
1037cadc0fa5SChuck Lever 		error = -EAFNOSUPPORT;
1038cadc0fa5SChuck Lever 
1039cadc0fa5SChuck Lever 	return error;
10402c7eb0b2SChuck Lever }
1041dfd56b8bSEric Dumazet #endif	/* IS_ENABLED(CONFIG_IPV6) */
10422c7eb0b2SChuck Lever 
10432c7eb0b2SChuck Lever /*
10442c7eb0b2SChuck Lever  * Register a kernel RPC service via rpcbind version 4.
10452c7eb0b2SChuck Lever  *
10462c7eb0b2SChuck Lever  * Returns zero on success; a negative errno value is returned
10472c7eb0b2SChuck Lever  * if any error occurs.
10482c7eb0b2SChuck Lever  */
__svc_register(struct net * net,const char * progname,const u32 program,const u32 version,const int family,const unsigned short protocol,const unsigned short port)10495247fab5SStanislav Kinsbursky static int __svc_register(struct net *net, const char *progname,
1050363f724cSChuck Lever 			  const u32 program, const u32 version,
10514b62e58cSChuck Lever 			  const int family,
10522c7eb0b2SChuck Lever 			  const unsigned short protocol,
10532c7eb0b2SChuck Lever 			  const unsigned short port)
10542c7eb0b2SChuck Lever {
1055363f724cSChuck Lever 	int error = -EAFNOSUPPORT;
10562c7eb0b2SChuck Lever 
1057a26cfad6SChuck Lever 	switch (family) {
10584b62e58cSChuck Lever 	case PF_INET:
10595247fab5SStanislav Kinsbursky 		error = __svc_rpcb_register4(net, program, version,
10602c7eb0b2SChuck Lever 						protocol, port);
1061cadc0fa5SChuck Lever 		break;
1062dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
10634b62e58cSChuck Lever 	case PF_INET6:
10645247fab5SStanislav Kinsbursky 		error = __svc_rpcb_register6(net, program, version,
10652c7eb0b2SChuck Lever 						protocol, port);
1066dfd56b8bSEric Dumazet #endif
10672c7eb0b2SChuck Lever 	}
10682c7eb0b2SChuck Lever 
106907a27305SChuck Lever 	trace_svc_register(progname, version, family, protocol, port, error);
1070a26cfad6SChuck Lever 	return error;
1071a26cfad6SChuck Lever }
1072a26cfad6SChuck Lever 
svc_rpcbind_set_version(struct net * net,const struct svc_program * progp,u32 version,int family,unsigned short proto,unsigned short port)1073642ee6b2STrond Myklebust int svc_rpcbind_set_version(struct net *net,
1074642ee6b2STrond Myklebust 			    const struct svc_program *progp,
1075642ee6b2STrond Myklebust 			    u32 version, int family,
1076642ee6b2STrond Myklebust 			    unsigned short proto,
1077642ee6b2STrond Myklebust 			    unsigned short port)
1078642ee6b2STrond Myklebust {
1079642ee6b2STrond Myklebust 	return __svc_register(net, progp->pg_name, progp->pg_prog,
1080642ee6b2STrond Myklebust 				version, family, proto, port);
1081642ee6b2STrond Myklebust 
1082642ee6b2STrond Myklebust }
1083642ee6b2STrond Myklebust EXPORT_SYMBOL_GPL(svc_rpcbind_set_version);
1084642ee6b2STrond Myklebust 
svc_generic_rpcbind_set(struct net * net,const struct svc_program * progp,u32 version,int family,unsigned short proto,unsigned short port)1085642ee6b2STrond Myklebust int svc_generic_rpcbind_set(struct net *net,
1086642ee6b2STrond Myklebust 			    const struct svc_program *progp,
1087642ee6b2STrond Myklebust 			    u32 version, int family,
1088642ee6b2STrond Myklebust 			    unsigned short proto,
1089642ee6b2STrond Myklebust 			    unsigned short port)
1090642ee6b2STrond Myklebust {
1091642ee6b2STrond Myklebust 	const struct svc_version *vers = progp->pg_vers[version];
1092642ee6b2STrond Myklebust 	int error;
1093642ee6b2STrond Myklebust 
1094642ee6b2STrond Myklebust 	if (vers == NULL)
1095642ee6b2STrond Myklebust 		return 0;
1096642ee6b2STrond Myklebust 
1097642ee6b2STrond Myklebust 	if (vers->vs_hidden) {
1098b4af5932SChuck Lever 		trace_svc_noregister(progp->pg_name, version, proto,
1099b4af5932SChuck Lever 				     port, family, 0);
1100642ee6b2STrond Myklebust 		return 0;
1101642ee6b2STrond Myklebust 	}
1102642ee6b2STrond Myklebust 
1103642ee6b2STrond Myklebust 	/*
1104642ee6b2STrond Myklebust 	 * Don't register a UDP port if we need congestion
1105642ee6b2STrond Myklebust 	 * control.
1106642ee6b2STrond Myklebust 	 */
1107642ee6b2STrond Myklebust 	if (vers->vs_need_cong_ctrl && proto == IPPROTO_UDP)
1108642ee6b2STrond Myklebust 		return 0;
1109642ee6b2STrond Myklebust 
1110642ee6b2STrond Myklebust 	error = svc_rpcbind_set_version(net, progp, version,
1111642ee6b2STrond Myklebust 					family, proto, port);
1112642ee6b2STrond Myklebust 
1113642ee6b2STrond Myklebust 	return (vers->vs_rpcb_optnl) ? 0 : error;
1114642ee6b2STrond Myklebust }
1115642ee6b2STrond Myklebust EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
1116642ee6b2STrond Myklebust 
1117a26cfad6SChuck Lever /**
1118a26cfad6SChuck Lever  * svc_register - register an RPC service with the local portmapper
1119a26cfad6SChuck Lever  * @serv: svc_serv struct for the service to register
11205247fab5SStanislav Kinsbursky  * @net: net namespace for the service to register
11214b62e58cSChuck Lever  * @family: protocol family of service's listener socket
1122a26cfad6SChuck Lever  * @proto: transport protocol number to advertise
1123a26cfad6SChuck Lever  * @port: port to advertise
1124a26cfad6SChuck Lever  *
11254b62e58cSChuck Lever  * Service is registered for any address in the passed-in protocol family
1126a26cfad6SChuck Lever  */
svc_register(const struct svc_serv * serv,struct net * net,const int family,const unsigned short proto,const unsigned short port)11275247fab5SStanislav Kinsbursky int svc_register(const struct svc_serv *serv, struct net *net,
11285247fab5SStanislav Kinsbursky 		 const int family, const unsigned short proto,
11295247fab5SStanislav Kinsbursky 		 const unsigned short port)
11301da177e4SLinus Torvalds {
11311da177e4SLinus Torvalds 	struct svc_program	*progp;
1132ea339d46SChuck Lever 	unsigned int		i;
113314aeb211SChuck Lever 	int			error = 0;
11341da177e4SLinus Torvalds 
11350af39507SWeston Andros Adamson 	WARN_ON_ONCE(proto == 0 && port == 0);
11360af39507SWeston Andros Adamson 	if (proto == 0 && port == 0)
11370af39507SWeston Andros Adamson 		return -EINVAL;
11381da177e4SLinus Torvalds 
1139bc5fea42SOlaf Kirch 	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
11401da177e4SLinus Torvalds 		for (i = 0; i < progp->pg_nvers; i++) {
1141bc5fea42SOlaf Kirch 
1142642ee6b2STrond Myklebust 			error = progp->pg_rpcbind_set(net, progp, i,
1143642ee6b2STrond Myklebust 					family, proto, port);
11447e55b59bSKinglong Mee 			if (error < 0) {
11457e55b59bSKinglong Mee 				printk(KERN_WARNING "svc: failed to register "
11467e55b59bSKinglong Mee 					"%sv%u RPC service (errno %d).\n",
11477e55b59bSKinglong Mee 					progp->pg_name, i, -error);
11481da177e4SLinus Torvalds 				break;
11491da177e4SLinus Torvalds 			}
1150bc5fea42SOlaf Kirch 		}
11517e55b59bSKinglong Mee 	}
11521da177e4SLinus Torvalds 
11537252d575SChuck Lever 	return error;
11547252d575SChuck Lever }
11557252d575SChuck Lever 
1156d5a8620fSChuck Lever /*
1157d5a8620fSChuck Lever  * If user space is running rpcbind, it should take the v4 UNSET
1158d5a8620fSChuck Lever  * and clear everything for this [program, version].  If user space
1159d5a8620fSChuck Lever  * is running portmap, it will reject the v4 UNSET, but won't have
1160d5a8620fSChuck Lever  * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
1161d5a8620fSChuck Lever  * in this case to clear all existing entries for [program, version].
1162d5a8620fSChuck Lever  */
__svc_unregister(struct net * net,const u32 program,const u32 version,const char * progname)11635247fab5SStanislav Kinsbursky static void __svc_unregister(struct net *net, const u32 program, const u32 version,
1164f6fb3f6fSChuck Lever 			     const char *progname)
1165f6fb3f6fSChuck Lever {
1166f6fb3f6fSChuck Lever 	int error;
1167f6fb3f6fSChuck Lever 
11685247fab5SStanislav Kinsbursky 	error = rpcb_v4_register(net, program, version, NULL, "");
1169d5a8620fSChuck Lever 
1170d5a8620fSChuck Lever 	/*
1171d5a8620fSChuck Lever 	 * User space didn't support rpcbind v4, so retry this
1172d5a8620fSChuck Lever 	 * request with the legacy rpcbind v2 protocol.
1173d5a8620fSChuck Lever 	 */
1174d5a8620fSChuck Lever 	if (error == -EPROTONOSUPPORT)
11755247fab5SStanislav Kinsbursky 		error = rpcb_register(net, program, version, 0, 0);
1176d5a8620fSChuck Lever 
1177b4af5932SChuck Lever 	trace_svc_unregister(progname, version, error);
1178f6fb3f6fSChuck Lever }
1179f6fb3f6fSChuck Lever 
11807252d575SChuck Lever /*
1181f6fb3f6fSChuck Lever  * All netids, bind addresses and ports registered for [program, version]
1182f6fb3f6fSChuck Lever  * are removed from the local rpcbind database (if the service is not
1183f6fb3f6fSChuck Lever  * hidden) to make way for a new instance of the service.
11847252d575SChuck Lever  *
1185f6fb3f6fSChuck Lever  * The result of unregistration is reported via dprintk for those who want
1186f6fb3f6fSChuck Lever  * verification of the result, but is otherwise not important.
11877252d575SChuck Lever  */
svc_unregister(const struct svc_serv * serv,struct net * net)11885247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net)
11897252d575SChuck Lever {
119000a87e5dSChuck Lever 	struct sighand_struct *sighand;
11917252d575SChuck Lever 	struct svc_program *progp;
11927252d575SChuck Lever 	unsigned long flags;
11937252d575SChuck Lever 	unsigned int i;
11947252d575SChuck Lever 
11957252d575SChuck Lever 	clear_thread_flag(TIF_SIGPENDING);
11967252d575SChuck Lever 
11977252d575SChuck Lever 	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
11987252d575SChuck Lever 		for (i = 0; i < progp->pg_nvers; i++) {
11997252d575SChuck Lever 			if (progp->pg_vers[i] == NULL)
12007252d575SChuck Lever 				continue;
12017252d575SChuck Lever 			if (progp->pg_vers[i]->vs_hidden)
12027252d575SChuck Lever 				continue;
12035247fab5SStanislav Kinsbursky 			__svc_unregister(net, progp->pg_prog, i, progp->pg_name);
12047252d575SChuck Lever 		}
12057252d575SChuck Lever 	}
12067252d575SChuck Lever 
120700a87e5dSChuck Lever 	rcu_read_lock();
120800a87e5dSChuck Lever 	sighand = rcu_dereference(current->sighand);
120900a87e5dSChuck Lever 	spin_lock_irqsave(&sighand->siglock, flags);
12101da177e4SLinus Torvalds 	recalc_sigpending();
121100a87e5dSChuck Lever 	spin_unlock_irqrestore(&sighand->siglock, flags);
121200a87e5dSChuck Lever 	rcu_read_unlock();
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds /*
12167032a3ddSJ. Bruce Fields  * dprintk the given error with the address of the client that caused it.
1217354ecbb9SDr. David Alan Gilbert  */
1218f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
1219b9075fa9SJoe Perches static __printf(2, 3)
svc_printk(struct svc_rqst * rqstp,const char * fmt,...)1220e87cc472SJoe Perches void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
1221354ecbb9SDr. David Alan Gilbert {
1222e87cc472SJoe Perches 	struct va_format vaf;
1223354ecbb9SDr. David Alan Gilbert 	va_list args;
1224354ecbb9SDr. David Alan Gilbert 	char 	buf[RPC_MAX_ADDRBUFLEN];
1225354ecbb9SDr. David Alan Gilbert 
1226354ecbb9SDr. David Alan Gilbert 	va_start(args, fmt);
1227354ecbb9SDr. David Alan Gilbert 
1228e87cc472SJoe Perches 	vaf.fmt = fmt;
1229e87cc472SJoe Perches 	vaf.va = &args;
1230e87cc472SJoe Perches 
12317032a3ddSJ. Bruce Fields 	dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf);
1232e87cc472SJoe Perches 
1233e87cc472SJoe Perches 	va_end(args);
1234354ecbb9SDr. David Alan Gilbert }
1235624ab464SJ. Bruce Fields #else
svc_printk(struct svc_rqst * rqstp,const char * fmt,...)1236624ab464SJ. Bruce Fields static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
1237624ab464SJ. Bruce Fields #endif
1238354ecbb9SDr. David Alan Gilbert 
12398e5b6773STrond Myklebust __be32
svc_generic_init_request(struct svc_rqst * rqstp,const struct svc_program * progp,struct svc_process_info * ret)12408e5b6773STrond Myklebust svc_generic_init_request(struct svc_rqst *rqstp,
12418e5b6773STrond Myklebust 		const struct svc_program *progp,
12428e5b6773STrond Myklebust 		struct svc_process_info *ret)
12438e5b6773STrond Myklebust {
12448e5b6773STrond Myklebust 	const struct svc_version *versp = NULL;	/* compiler food */
12458e5b6773STrond Myklebust 	const struct svc_procedure *procp = NULL;
12468e5b6773STrond Myklebust 
12478e5b6773STrond Myklebust 	if (rqstp->rq_vers >= progp->pg_nvers )
12488e5b6773STrond Myklebust 		goto err_bad_vers;
12498e5b6773STrond Myklebust 	versp = progp->pg_vers[rqstp->rq_vers];
12508e5b6773STrond Myklebust 	if (!versp)
12518e5b6773STrond Myklebust 		goto err_bad_vers;
12528e5b6773STrond Myklebust 
12538e5b6773STrond Myklebust 	/*
12548e5b6773STrond Myklebust 	 * Some protocol versions (namely NFSv4) require some form of
12558e5b6773STrond Myklebust 	 * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
12568e5b6773STrond Myklebust 	 * In other words, UDP is not allowed. We mark those when setting
12578e5b6773STrond Myklebust 	 * up the svc_xprt, and verify that here.
12588e5b6773STrond Myklebust 	 *
12598e5b6773STrond Myklebust 	 * The spec is not very clear about what error should be returned
12608e5b6773STrond Myklebust 	 * when someone tries to access a server that is listening on UDP
12618e5b6773STrond Myklebust 	 * for lower versions. RPC_PROG_MISMATCH seems to be the closest
12628e5b6773STrond Myklebust 	 * fit.
12638e5b6773STrond Myklebust 	 */
12648e5b6773STrond Myklebust 	if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
12658e5b6773STrond Myklebust 	    !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
12668e5b6773STrond Myklebust 		goto err_bad_vers;
12678e5b6773STrond Myklebust 
12688e5b6773STrond Myklebust 	if (rqstp->rq_proc >= versp->vs_nproc)
12698e5b6773STrond Myklebust 		goto err_bad_proc;
12708e5b6773STrond Myklebust 	rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
12718e5b6773STrond Myklebust 
12728e5b6773STrond Myklebust 	/* Initialize storage for argp and resp */
1273103cc1faSChuck Lever 	memset(rqstp->rq_argp, 0, procp->pc_argzero);
12748e5b6773STrond Myklebust 	memset(rqstp->rq_resp, 0, procp->pc_ressize);
12758e5b6773STrond Myklebust 
12768e5b6773STrond Myklebust 	/* Bump per-procedure stats counter */
127765ba3d24SChuck Lever 	this_cpu_inc(versp->vs_count[rqstp->rq_proc]);
12788e5b6773STrond Myklebust 
12798e5b6773STrond Myklebust 	ret->dispatch = versp->vs_dispatch;
12808e5b6773STrond Myklebust 	return rpc_success;
12818e5b6773STrond Myklebust err_bad_vers:
12828e5b6773STrond Myklebust 	ret->mismatch.lovers = progp->pg_lovers;
12838e5b6773STrond Myklebust 	ret->mismatch.hivers = progp->pg_hivers;
12848e5b6773STrond Myklebust 	return rpc_prog_mismatch;
12858e5b6773STrond Myklebust err_bad_proc:
12868e5b6773STrond Myklebust 	return rpc_proc_unavail;
12878e5b6773STrond Myklebust }
12888e5b6773STrond Myklebust EXPORT_SYMBOL_GPL(svc_generic_init_request);
12898e5b6773STrond Myklebust 
1290354ecbb9SDr. David Alan Gilbert /*
12911cad7ea6SRicardo Labiaga  * Common routine for processing the RPC request.
12921da177e4SLinus Torvalds  */
12931cad7ea6SRicardo Labiaga static int
svc_process_common(struct svc_rqst * rqstp)12945f69d5f6SChuck Lever svc_process_common(struct svc_rqst *rqstp)
12951da177e4SLinus Torvalds {
1296649a692eSChuck Lever 	struct xdr_stream	*xdr = &rqstp->rq_res_stream;
12971da177e4SLinus Torvalds 	struct svc_program	*progp;
1298860bda29SChristoph Hellwig 	const struct svc_procedure *procp = NULL;
12996fb2b47fSNeilBrown 	struct svc_serv		*serv = rqstp->rq_server;
13008e5b6773STrond Myklebust 	struct svc_process_info process;
130178c542f9SChuck Lever 	enum svc_auth_status	auth_res;
1302649a692eSChuck Lever 	unsigned int		aoffset;
130378c542f9SChuck Lever 	int			rc;
1304cee4db19SChuck Lever 	__be32			*p;
13051da177e4SLinus Torvalds 
130606eb8a56SChuck Lever 	/* Will be turned off by GSS integrity and privacy services */
13077827c81fSChuck Lever 	set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
13082f425878SAndy Adamson 	/* Will be turned off only when NFSv4 Sessions are used */
13097827c81fSChuck Lever 	set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
13107827c81fSChuck Lever 	clear_bit(RQ_DROPME, &rqstp->rq_flags);
1311e831fe65STom Tucker 
13122009e329SChuck Lever 	/* Construct the first words of the reply: */
1313649a692eSChuck Lever 	svcxdr_init_encode(rqstp);
1314649a692eSChuck Lever 	xdr_stream_encode_be32(xdr, rqstp->rq_xid);
1315649a692eSChuck Lever 	xdr_stream_encode_be32(xdr, rpc_reply);
13161da177e4SLinus Torvalds 
1317163cdfcaSChuck Lever 	p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 4);
1318163cdfcaSChuck Lever 	if (unlikely(!p))
1319163cdfcaSChuck Lever 		goto err_short_len;
1320163cdfcaSChuck Lever 	if (*p++ != cpu_to_be32(RPC_VERSION))
13211da177e4SLinus Torvalds 		goto err_bad_rpc;
13221da177e4SLinus Torvalds 
1323649a692eSChuck Lever 	xdr_stream_encode_be32(xdr, rpc_msg_accepted);
13241da177e4SLinus Torvalds 
1325163cdfcaSChuck Lever 	rqstp->rq_prog = be32_to_cpup(p++);
1326163cdfcaSChuck Lever 	rqstp->rq_vers = be32_to_cpup(p++);
1327163cdfcaSChuck Lever 	rqstp->rq_proc = be32_to_cpup(p);
13281da177e4SLinus Torvalds 
132980d188a6SNeilBrown 	for (progp = serv->sv_program; progp; progp = progp->pg_next)
13304119bd03SChuck Lever 		if (rqstp->rq_prog == progp->pg_prog)
133180d188a6SNeilBrown 			break;
133280d188a6SNeilBrown 
13331da177e4SLinus Torvalds 	/*
13341da177e4SLinus Torvalds 	 * Decode auth data, and add verifier to reply buffer.
13351da177e4SLinus Torvalds 	 * We do this before anything else in order to get a decent
13361da177e4SLinus Torvalds 	 * auth verifier.
13371da177e4SLinus Torvalds 	 */
1338438623a0SChuck Lever 	auth_res = svc_authenticate(rqstp);
13391da177e4SLinus Torvalds 	/* Also give the program a chance to reject this call: */
13405c2465dfSChuck Lever 	if (auth_res == SVC_OK && progp)
13411da177e4SLinus Torvalds 		auth_res = progp->pg_authenticate(rqstp);
1342438623a0SChuck Lever 	trace_svc_authenticate(rqstp, auth_res);
13431da177e4SLinus Torvalds 	switch (auth_res) {
13441da177e4SLinus Torvalds 	case SVC_OK:
13451da177e4SLinus Torvalds 		break;
13461da177e4SLinus Torvalds 	case SVC_GARBAGE:
13476d037b15SChuck Lever 		goto err_garbage_args;
13481da177e4SLinus Torvalds 	case SVC_SYSERR:
13496d037b15SChuck Lever 		goto err_system_err;
13501da177e4SLinus Torvalds 	case SVC_DENIED:
13511da177e4SLinus Torvalds 		goto err_bad_auth;
13521ebede86SNeilBrown 	case SVC_CLOSE:
13534d712ef1SChuck Lever 		goto close;
13541da177e4SLinus Torvalds 	case SVC_DROP:
13551da177e4SLinus Torvalds 		goto dropit;
13561da177e4SLinus Torvalds 	case SVC_COMPLETE:
13571da177e4SLinus Torvalds 		goto sendit;
135878c542f9SChuck Lever 	default:
135978c542f9SChuck Lever 		pr_warn_once("Unexpected svc_auth_status (%d)\n", auth_res);
136078c542f9SChuck Lever 		goto err_system_err;
13611da177e4SLinus Torvalds 	}
13621da177e4SLinus Torvalds 
13639ba02638SAndreas Gruenbacher 	if (progp == NULL)
13641da177e4SLinus Torvalds 		goto err_bad_prog;
13651da177e4SLinus Torvalds 
13666d037b15SChuck Lever 	switch (progp->pg_init_request(rqstp, progp, &process)) {
13678e5b6773STrond Myklebust 	case rpc_success:
13688e5b6773STrond Myklebust 		break;
13698e5b6773STrond Myklebust 	case rpc_prog_unavail:
13708e5b6773STrond Myklebust 		goto err_bad_prog;
13718e5b6773STrond Myklebust 	case rpc_prog_mismatch:
13721da177e4SLinus Torvalds 		goto err_bad_vers;
13738e5b6773STrond Myklebust 	case rpc_proc_unavail:
13741da177e4SLinus Torvalds 		goto err_bad_proc;
13758e5b6773STrond Myklebust 	}
13768e5b6773STrond Myklebust 
13778e5b6773STrond Myklebust 	procp = rqstp->rq_procinfo;
13788e5b6773STrond Myklebust 	/* Should this check go into the dispatcher? */
13798e5b6773STrond Myklebust 	if (!procp || !procp->pc_func)
13808e5b6773STrond Myklebust 		goto err_bad_proc;
13811da177e4SLinus Torvalds 
13821da177e4SLinus Torvalds 	/* Syntactic check complete */
13831257fe22SJosef Bacik 	if (serv->sv_stats)
13841da177e4SLinus Torvalds 		serv->sv_stats->rpccnt++;
13850b9547bfSChuck Lever 	trace_svc_process(rqstp, progp->pg_name);
13861da177e4SLinus Torvalds 
1387649a692eSChuck Lever 	aoffset = xdr_stream_pos(xdr);
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds 	/* un-reserve some of the out-queue now that we have a
13901da177e4SLinus Torvalds 	 * better idea of reply size
13911da177e4SLinus Torvalds 	 */
13921da177e4SLinus Torvalds 	if (procp->pc_xdrressize)
1393cd123012SJeff Layton 		svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds 	/* Call the function that processes the request. */
1396cee4db19SChuck Lever 	rc = process.dispatch(rqstp);
13975b747a59SChuck Lever 	if (procp->pc_release)
13985b747a59SChuck Lever 		procp->pc_release(rqstp);
139961182c79SAnna Schumaker 	xdr_finish_decode(xdr);
140061182c79SAnna Schumaker 
14015b747a59SChuck Lever 	if (!rc)
14025b747a59SChuck Lever 		goto dropit;
14039082e1d9SChuck Lever 	if (rqstp->rq_auth_stat != rpc_auth_ok)
14045b747a59SChuck Lever 		goto err_bad_auth;
14059082e1d9SChuck Lever 
1406cee4db19SChuck Lever 	if (*rqstp->rq_accept_statp != rpc_success)
1407649a692eSChuck Lever 		xdr_truncate_encode(xdr, aoffset);
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds 	if (procp->pc_encode == NULL)
14101da177e4SLinus Torvalds 		goto dropit;
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds  sendit:
14131da177e4SLinus Torvalds 	if (svc_authorise(rqstp))
1414f1442d63SDaniel Kobras 		goto close_xprt;
14151cad7ea6SRicardo Labiaga 	return 1;		/* Caller can now send it */
14161da177e4SLinus Torvalds 
14171da177e4SLinus Torvalds  dropit:
14181da177e4SLinus Torvalds 	svc_authorise(rqstp);	/* doesn't hurt to call this twice */
14191da177e4SLinus Torvalds 	dprintk("svc: svc_process dropit\n");
14201da177e4SLinus Torvalds 	return 0;
14211da177e4SLinus Torvalds 
14224d712ef1SChuck Lever  close:
1423f1442d63SDaniel Kobras 	svc_authorise(rqstp);
1424f1442d63SDaniel Kobras close_xprt:
1425d4b09acfSVasily Averin 	if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
14264355d767SChuck Lever 		svc_xprt_close(rqstp->rq_xprt);
14274d712ef1SChuck Lever 	dprintk("svc: svc_process close\n");
14284d712ef1SChuck Lever 	return 0;
14294d712ef1SChuck Lever 
14301da177e4SLinus Torvalds err_short_len:
14311c59a532SChuck Lever 	svc_printk(rqstp, "short len %u, dropping request\n",
14321c59a532SChuck Lever 		   rqstp->rq_arg.len);
1433f1442d63SDaniel Kobras 	goto close_xprt;
14341da177e4SLinus Torvalds 
14351da177e4SLinus Torvalds err_bad_rpc:
14361257fe22SJosef Bacik 	if (serv->sv_stats)
14371da177e4SLinus Torvalds 		serv->sv_stats->rpcbadfmt++;
1438649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
1439649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_MISMATCH);
1440649a692eSChuck Lever 	/* Only RPCv2 supported */
1441649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_VERSION);
1442649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_VERSION);
144329cd2927SChuck Lever 	return 1;	/* don't wrap */
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds err_bad_auth:
1446438623a0SChuck Lever 	dprintk("svc: authentication failed (%d)\n",
1447438623a0SChuck Lever 		be32_to_cpu(rqstp->rq_auth_stat));
14481257fe22SJosef Bacik 	if (serv->sv_stats)
14491da177e4SLinus Torvalds 		serv->sv_stats->rpcbadauth++;
1450649a692eSChuck Lever 	/* Restore write pointer to location of reply status: */
1451649a692eSChuck Lever 	xdr_truncate_encode(xdr, XDR_UNIT * 2);
1452649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
1453649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, RPC_AUTH_ERROR);
1454649a692eSChuck Lever 	xdr_stream_encode_be32(xdr, rqstp->rq_auth_stat);
14551da177e4SLinus Torvalds 	goto sendit;
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds err_bad_prog:
14584119bd03SChuck Lever 	dprintk("svc: unknown program %d\n", rqstp->rq_prog);
14591257fe22SJosef Bacik 	if (serv->sv_stats)
14601da177e4SLinus Torvalds 		serv->sv_stats->rpcbadfmt++;
146129cd2927SChuck Lever 	*rqstp->rq_accept_statp = rpc_prog_unavail;
14621da177e4SLinus Torvalds 	goto sendit;
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds err_bad_vers:
1465354ecbb9SDr. David Alan Gilbert 	svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
14668e5b6773STrond Myklebust 		       rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
146734e9a63bSNeilBrown 
14681257fe22SJosef Bacik 	if (serv->sv_stats)
14691da177e4SLinus Torvalds 		serv->sv_stats->rpcbadfmt++;
147029cd2927SChuck Lever 	*rqstp->rq_accept_statp = rpc_prog_mismatch;
147129cd2927SChuck Lever 
147229cd2927SChuck Lever 	/*
147329cd2927SChuck Lever 	 * svc_authenticate() has already added the verifier and
147429cd2927SChuck Lever 	 * advanced the stream just past rq_accept_statp.
147529cd2927SChuck Lever 	 */
1476649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, process.mismatch.lovers);
1477649a692eSChuck Lever 	xdr_stream_encode_u32(xdr, process.mismatch.hivers);
14781da177e4SLinus Torvalds 	goto sendit;
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds err_bad_proc:
14818e5b6773STrond Myklebust 	svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
148234e9a63bSNeilBrown 
14831257fe22SJosef Bacik 	if (serv->sv_stats)
14841da177e4SLinus Torvalds 		serv->sv_stats->rpcbadfmt++;
148529cd2927SChuck Lever 	*rqstp->rq_accept_statp = rpc_proc_unavail;
14861da177e4SLinus Torvalds 	goto sendit;
14871da177e4SLinus Torvalds 
14886d037b15SChuck Lever err_garbage_args:
14896d037b15SChuck Lever 	svc_printk(rqstp, "failed to decode RPC header\n");
149034e9a63bSNeilBrown 
14911257fe22SJosef Bacik 	if (serv->sv_stats)
14921da177e4SLinus Torvalds 		serv->sv_stats->rpcbadfmt++;
149329cd2927SChuck Lever 	*rqstp->rq_accept_statp = rpc_garbage_args;
14946d037b15SChuck Lever 	goto sendit;
14956d037b15SChuck Lever 
14966d037b15SChuck Lever err_system_err:
14971257fe22SJosef Bacik 	if (serv->sv_stats)
14986d037b15SChuck Lever 		serv->sv_stats->rpcbadfmt++;
149929cd2927SChuck Lever 	*rqstp->rq_accept_statp = rpc_system_err;
15001da177e4SLinus Torvalds 	goto sendit;
15011da177e4SLinus Torvalds }
15027adae489SGreg Banks 
150355fcc7d9SChuck Lever /**
150455fcc7d9SChuck Lever  * svc_process - Execute one RPC transaction
150555fcc7d9SChuck Lever  * @rqstp: RPC transaction context
150655fcc7d9SChuck Lever  *
15071cad7ea6SRicardo Labiaga  */
svc_process(struct svc_rqst * rqstp)150855fcc7d9SChuck Lever void svc_process(struct svc_rqst *rqstp)
15091cad7ea6SRicardo Labiaga {
15101cad7ea6SRicardo Labiaga 	struct kvec		*resv = &rqstp->rq_res.head[0];
1511f4afc8feSChuck Lever 	__be32 *p;
15121cad7ea6SRicardo Labiaga 
15133a126180SChuck Lever #if IS_ENABLED(CONFIG_FAIL_SUNRPC)
15143a126180SChuck Lever 	if (!fail_sunrpc.ignore_server_disconnect &&
15153a126180SChuck Lever 	    should_fail(&fail_sunrpc.attr, 1))
15163a126180SChuck Lever 		svc_xprt_deferred_close(rqstp->rq_xprt);
15173a126180SChuck Lever #endif
15183a126180SChuck Lever 
15191cad7ea6SRicardo Labiaga 	/*
15201cad7ea6SRicardo Labiaga 	 * Setup response xdr_buf.
15211cad7ea6SRicardo Labiaga 	 * Initially it has just one page
15221cad7ea6SRicardo Labiaga 	 */
1523afc59400SJ. Bruce Fields 	rqstp->rq_next_page = &rqstp->rq_respages[1];
15241cad7ea6SRicardo Labiaga 	resv->iov_base = page_address(rqstp->rq_respages[0]);
15251cad7ea6SRicardo Labiaga 	resv->iov_len = 0;
152681593c4dSChuck Lever 	rqstp->rq_res.pages = rqstp->rq_next_page;
15271cad7ea6SRicardo Labiaga 	rqstp->rq_res.len = 0;
15281cad7ea6SRicardo Labiaga 	rqstp->rq_res.page_base = 0;
15291cad7ea6SRicardo Labiaga 	rqstp->rq_res.page_len = 0;
15301cad7ea6SRicardo Labiaga 	rqstp->rq_res.buflen = PAGE_SIZE;
15311cad7ea6SRicardo Labiaga 	rqstp->rq_res.tail[0].iov_base = NULL;
15321cad7ea6SRicardo Labiaga 	rqstp->rq_res.tail[0].iov_len = 0;
15331cad7ea6SRicardo Labiaga 
1534f4afc8feSChuck Lever 	svcxdr_init_decode(rqstp);
1535f4afc8feSChuck Lever 	p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2);
1536f4afc8feSChuck Lever 	if (unlikely(!p))
1537f4afc8feSChuck Lever 		goto out_drop;
1538f4afc8feSChuck Lever 	rqstp->rq_xid = *p++;
1539f4afc8feSChuck Lever 	if (unlikely(*p != rpc_call))
154081593c4dSChuck Lever 		goto out_baddir;
1541f4afc8feSChuck Lever 
15425f69d5f6SChuck Lever 	if (!svc_process_common(rqstp))
1543860a0d9eSJeff Layton 		goto out_drop;
154455fcc7d9SChuck Lever 	svc_send(rqstp);
154555fcc7d9SChuck Lever 	return;
1546860a0d9eSJeff Layton 
154781593c4dSChuck Lever out_baddir:
154881593c4dSChuck Lever 	svc_printk(rqstp, "bad direction 0x%08x, dropping request\n",
1549f4afc8feSChuck Lever 		   be32_to_cpu(*p));
15501257fe22SJosef Bacik 	if (rqstp->rq_server->sv_stats)
155181593c4dSChuck Lever 		rqstp->rq_server->sv_stats->rpcbadfmt++;
1552860a0d9eSJeff Layton out_drop:
15534b5b3ba1SAndy Adamson 	svc_drop(rqstp);
15544b5b3ba1SAndy Adamson }
15551cad7ea6SRicardo Labiaga 
15569e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL)
15574d6bbb62SRicardo Labiaga /*
15584d6bbb62SRicardo Labiaga  * Process a backchannel RPC request that arrived over an existing
15594d6bbb62SRicardo Labiaga  * outbound connection
15604d6bbb62SRicardo Labiaga  */
15614d6bbb62SRicardo Labiaga int
bc_svc_process(struct svc_serv * serv,struct rpc_rqst * req,struct svc_rqst * rqstp)15624d6bbb62SRicardo Labiaga bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
15634d6bbb62SRicardo Labiaga 	       struct svc_rqst *rqstp)
15644d6bbb62SRicardo Labiaga {
1565632dda83SChuck Lever 	struct rpc_task *task;
15660d2a970dSTrond Myklebust 	int proc_error;
1567632dda83SChuck Lever 	int error;
1568632dda83SChuck Lever 
1569632dda83SChuck Lever 	dprintk("svc: %s(%p)\n", __func__, req);
15704d6bbb62SRicardo Labiaga 
15714d6bbb62SRicardo Labiaga 	/* Build the svc_rqst used by the common processing routine */
15724d6bbb62SRicardo Labiaga 	rqstp->rq_xid = req->rq_xid;
15734d6bbb62SRicardo Labiaga 	rqstp->rq_prot = req->rq_xprt->prot;
15744d6bbb62SRicardo Labiaga 	rqstp->rq_server = serv;
1575d4b09acfSVasily Averin 	rqstp->rq_bc_net = req->rq_xprt->xprt_net;
15764d6bbb62SRicardo Labiaga 
15774d6bbb62SRicardo Labiaga 	rqstp->rq_addrlen = sizeof(req->rq_xprt->addr);
15784d6bbb62SRicardo Labiaga 	memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
15794d6bbb62SRicardo Labiaga 	memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
15804d6bbb62SRicardo Labiaga 	memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
1581756b9b37STrond Myklebust 
1582756b9b37STrond Myklebust 	/* Adjust the argument buffer length */
158338b7631fSBenjamin Coddington 	rqstp->rq_arg.len = req->rq_private_buf.len;
1584756b9b37STrond Myklebust 	if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
1585756b9b37STrond Myklebust 		rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
1586756b9b37STrond Myklebust 		rqstp->rq_arg.page_len = 0;
1587756b9b37STrond Myklebust 	} else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len +
1588756b9b37STrond Myklebust 			rqstp->rq_arg.page_len)
1589756b9b37STrond Myklebust 		rqstp->rq_arg.page_len = rqstp->rq_arg.len -
1590756b9b37STrond Myklebust 			rqstp->rq_arg.head[0].iov_len;
1591756b9b37STrond Myklebust 	else
1592756b9b37STrond Myklebust 		rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len +
1593756b9b37STrond Myklebust 			rqstp->rq_arg.page_len;
15944d6bbb62SRicardo Labiaga 
15955f69d5f6SChuck Lever 	/* Reset the response buffer */
15965f69d5f6SChuck Lever 	rqstp->rq_res.head[0].iov_len = 0;
1597f4afc8feSChuck Lever 
15984d6bbb62SRicardo Labiaga 	/*
1599f4afc8feSChuck Lever 	 * Skip the XID and calldir fields because they've already
1600f4afc8feSChuck Lever 	 * been processed by the caller.
16014d6bbb62SRicardo Labiaga 	 */
16025f69d5f6SChuck Lever 	svcxdr_init_decode(rqstp);
1603f4afc8feSChuck Lever 	if (!xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2)) {
1604f4afc8feSChuck Lever 		error = -EINVAL;
1605f4afc8feSChuck Lever 		goto out;
1606f4afc8feSChuck Lever 	}
16074d6bbb62SRicardo Labiaga 
1608632dda83SChuck Lever 	/* Parse and execute the bc call */
16095f69d5f6SChuck Lever 	proc_error = svc_process_common(rqstp);
16100d2a970dSTrond Myklebust 
16117402a4feSTrond Myklebust 	atomic_dec(&req->rq_xprt->bc_slot_count);
16120d2a970dSTrond Myklebust 	if (!proc_error) {
1613632dda83SChuck Lever 		/* Processing error: drop the request */
1614b3b02ae5STrond Myklebust 		xprt_free_bc_request(req);
16158f7766c8SVasily Averin 		error = -EINVAL;
16168f7766c8SVasily Averin 		goto out;
16174b5b3ba1SAndy Adamson 	}
1618632dda83SChuck Lever 	/* Finally, send the reply synchronously */
1619632dda83SChuck Lever 	memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf));
16200f419791STrond Myklebust 	task = rpc_run_bc_task(req);
1621632dda83SChuck Lever 	if (IS_ERR(task)) {
1622632dda83SChuck Lever 		error = PTR_ERR(task);
1623632dda83SChuck Lever 		goto out;
1624632dda83SChuck Lever 	}
1625632dda83SChuck Lever 
1626632dda83SChuck Lever 	WARN_ON_ONCE(atomic_read(&task->tk_count) != 1);
1627632dda83SChuck Lever 	error = task->tk_status;
1628632dda83SChuck Lever 	rpc_put_task(task);
1629632dda83SChuck Lever 
1630632dda83SChuck Lever out:
1631632dda83SChuck Lever 	dprintk("svc: %s(), error=%d\n", __func__, error);
1632632dda83SChuck Lever 	return error;
16334d6bbb62SRicardo Labiaga }
16340d961aa9STrond Myklebust EXPORT_SYMBOL_GPL(bc_svc_process);
16359e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */
16364d6bbb62SRicardo Labiaga 
1637f18d8afbSChuck Lever /**
1638f18d8afbSChuck Lever  * svc_max_payload - Return transport-specific limit on the RPC payload
1639f18d8afbSChuck Lever  * @rqstp: RPC transaction context
1640f18d8afbSChuck Lever  *
1641f18d8afbSChuck Lever  * Returns the maximum number of payload bytes the current transport
1642f18d8afbSChuck Lever  * allows.
16437adae489SGreg Banks  */
svc_max_payload(const struct svc_rqst * rqstp)16447adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp)
16457adae489SGreg Banks {
164649023155STom Tucker 	u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
16477adae489SGreg Banks 
1648c6b0a9f8SNeilBrown 	if (rqstp->rq_server->sv_max_payload < max)
1649c6b0a9f8SNeilBrown 		max = rqstp->rq_server->sv_max_payload;
16507adae489SGreg Banks 	return max;
16517adae489SGreg Banks }
16527adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload);
16538154ef27SChuck Lever 
16548154ef27SChuck Lever /**
16555c117207SChuck Lever  * svc_proc_name - Return RPC procedure name in string form
16565c117207SChuck Lever  * @rqstp: svc_rqst to operate on
16575c117207SChuck Lever  *
16585c117207SChuck Lever  * Return value:
16595c117207SChuck Lever  *   Pointer to a NUL-terminated string
16605c117207SChuck Lever  */
svc_proc_name(const struct svc_rqst * rqstp)16615c117207SChuck Lever const char *svc_proc_name(const struct svc_rqst *rqstp)
16625c117207SChuck Lever {
16635c117207SChuck Lever 	if (rqstp && rqstp->rq_procinfo)
16645c117207SChuck Lever 		return rqstp->rq_procinfo->pc_name;
16655c117207SChuck Lever 	return "unknown";
16665c117207SChuck Lever }
16675c117207SChuck Lever 
16685c117207SChuck Lever 
16695c117207SChuck Lever /**
167003493bcaSChuck Lever  * svc_encode_result_payload - mark a range of bytes as a result payload
167141205539SChuck Lever  * @rqstp: svc_rqst to operate on
167241205539SChuck Lever  * @offset: payload's byte offset in rqstp->rq_res
167341205539SChuck Lever  * @length: size of payload, in bytes
167441205539SChuck Lever  *
167541205539SChuck Lever  * Returns zero on success, or a negative errno if a permanent
167641205539SChuck Lever  * error occurred.
167741205539SChuck Lever  */
svc_encode_result_payload(struct svc_rqst * rqstp,unsigned int offset,unsigned int length)167803493bcaSChuck Lever int svc_encode_result_payload(struct svc_rqst *rqstp, unsigned int offset,
167941205539SChuck Lever 			      unsigned int length)
168041205539SChuck Lever {
168103493bcaSChuck Lever 	return rqstp->rq_xprt->xpt_ops->xpo_result_payload(rqstp, offset,
168203493bcaSChuck Lever 							   length);
168341205539SChuck Lever }
168403493bcaSChuck Lever EXPORT_SYMBOL_GPL(svc_encode_result_payload);
168541205539SChuck Lever 
168641205539SChuck Lever /**
16878154ef27SChuck Lever  * svc_fill_write_vector - Construct data argument for VFS write call
16888154ef27SChuck Lever  * @rqstp: svc_rqst to operate on
1689dae9a6caSChuck Lever  * @payload: xdr_buf containing only the write data payload
16908154ef27SChuck Lever  *
16913fd9557aSChuck Lever  * Fills in rqstp::rq_vec, and returns the number of elements.
16928154ef27SChuck Lever  */
svc_fill_write_vector(struct svc_rqst * rqstp,struct xdr_buf * payload)1693dae9a6caSChuck Lever unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
1694dae9a6caSChuck Lever 				   struct xdr_buf *payload)
16958154ef27SChuck Lever {
1696dae9a6caSChuck Lever 	struct page **pages = payload->pages;
1697dae9a6caSChuck Lever 	struct kvec *first = payload->head;
16988154ef27SChuck Lever 	struct kvec *vec = rqstp->rq_vec;
1699dae9a6caSChuck Lever 	size_t total = payload->len;
17008154ef27SChuck Lever 	unsigned int i;
17018154ef27SChuck Lever 
17028154ef27SChuck Lever 	/* Some types of transport can present the write payload
17038154ef27SChuck Lever 	 * entirely in rq_arg.pages. In this case, @first is empty.
17048154ef27SChuck Lever 	 */
17058154ef27SChuck Lever 	i = 0;
17068154ef27SChuck Lever 	if (first->iov_len) {
17078154ef27SChuck Lever 		vec[i].iov_base = first->iov_base;
17088154ef27SChuck Lever 		vec[i].iov_len = min_t(size_t, total, first->iov_len);
17098154ef27SChuck Lever 		total -= vec[i].iov_len;
17108154ef27SChuck Lever 		++i;
17118154ef27SChuck Lever 	}
17128154ef27SChuck Lever 
17138154ef27SChuck Lever 	while (total) {
17148154ef27SChuck Lever 		vec[i].iov_base = page_address(*pages);
17158154ef27SChuck Lever 		vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
17168154ef27SChuck Lever 		total -= vec[i].iov_len;
17178154ef27SChuck Lever 		++i;
17188154ef27SChuck Lever 		++pages;
17198154ef27SChuck Lever 	}
17208154ef27SChuck Lever 
17218154ef27SChuck Lever 	WARN_ON_ONCE(i > ARRAY_SIZE(rqstp->rq_vec));
17228154ef27SChuck Lever 	return i;
17238154ef27SChuck Lever }
17248154ef27SChuck Lever EXPORT_SYMBOL_GPL(svc_fill_write_vector);
172538a70315SChuck Lever 
172638a70315SChuck Lever /**
172738a70315SChuck Lever  * svc_fill_symlink_pathname - Construct pathname argument for VFS symlink call
172838a70315SChuck Lever  * @rqstp: svc_rqst to operate on
172938a70315SChuck Lever  * @first: buffer containing first section of pathname
173011b4d66eSChuck Lever  * @p: buffer containing remaining section of pathname
173138a70315SChuck Lever  * @total: total length of the pathname argument
173238a70315SChuck Lever  *
173311b4d66eSChuck Lever  * The VFS symlink API demands a NUL-terminated pathname in mapped memory.
173411b4d66eSChuck Lever  * Returns pointer to a NUL-terminated string, or an ERR_PTR. Caller must free
173511b4d66eSChuck Lever  * the returned string.
173638a70315SChuck Lever  */
svc_fill_symlink_pathname(struct svc_rqst * rqstp,struct kvec * first,void * p,size_t total)173738a70315SChuck Lever char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, struct kvec *first,
173811b4d66eSChuck Lever 				void *p, size_t total)
173938a70315SChuck Lever {
174038a70315SChuck Lever 	size_t len, remaining;
174111b4d66eSChuck Lever 	char *result, *dst;
174238a70315SChuck Lever 
174311b4d66eSChuck Lever 	result = kmalloc(total + 1, GFP_KERNEL);
174411b4d66eSChuck Lever 	if (!result)
174511b4d66eSChuck Lever 		return ERR_PTR(-ESERVERFAULT);
174611b4d66eSChuck Lever 
174738a70315SChuck Lever 	dst = result;
174838a70315SChuck Lever 	remaining = total;
174938a70315SChuck Lever 
175038a70315SChuck Lever 	len = min_t(size_t, total, first->iov_len);
175111b4d66eSChuck Lever 	if (len) {
175238a70315SChuck Lever 		memcpy(dst, first->iov_base, len);
175338a70315SChuck Lever 		dst += len;
175438a70315SChuck Lever 		remaining -= len;
175511b4d66eSChuck Lever 	}
175638a70315SChuck Lever 
175738a70315SChuck Lever 	if (remaining) {
175838a70315SChuck Lever 		len = min_t(size_t, remaining, PAGE_SIZE);
175911b4d66eSChuck Lever 		memcpy(dst, p, len);
176038a70315SChuck Lever 		dst += len;
176138a70315SChuck Lever 	}
176238a70315SChuck Lever 
176338a70315SChuck Lever 	*dst = '\0';
176438a70315SChuck Lever 
176511b4d66eSChuck Lever 	/* Sanity check: Linux doesn't allow the pathname argument to
176638a70315SChuck Lever 	 * contain a NUL byte.
176738a70315SChuck Lever 	 */
176811b4d66eSChuck Lever 	if (strlen(result) != total) {
176911b4d66eSChuck Lever 		kfree(result);
177038a70315SChuck Lever 		return ERR_PTR(-EINVAL);
177111b4d66eSChuck Lever 	}
177238a70315SChuck Lever 	return result;
177338a70315SChuck Lever }
177438a70315SChuck Lever EXPORT_SYMBOL_GPL(svc_fill_symlink_pathname);
1775