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