162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/net/sunrpc/svc.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * High-level RPC service routines
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Multiple threads pools and NUMAisation
1062306a36Sopenharmony_ci * Copyright (c) 2006 Silicon Graphics, Inc.
1162306a36Sopenharmony_ci * by Greg Banks <gnb@melbourne.sgi.com>
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/linkage.h>
1562306a36Sopenharmony_ci#include <linux/sched/signal.h>
1662306a36Sopenharmony_ci#include <linux/errno.h>
1762306a36Sopenharmony_ci#include <linux/net.h>
1862306a36Sopenharmony_ci#include <linux/in.h>
1962306a36Sopenharmony_ci#include <linux/mm.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/kthread.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/sunrpc/types.h>
2662306a36Sopenharmony_ci#include <linux/sunrpc/xdr.h>
2762306a36Sopenharmony_ci#include <linux/sunrpc/stats.h>
2862306a36Sopenharmony_ci#include <linux/sunrpc/svcsock.h>
2962306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
3062306a36Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <trace/events/sunrpc.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "fail.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define RPCDBG_FACILITY	RPCDBG_SVCDSP
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void svc_unregister(const struct svc_serv *serv, struct net *net);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define SVC_POOL_DEFAULT	SVC_POOL_GLOBAL
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * Mode for mapping cpus to pools.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cienum {
4662306a36Sopenharmony_ci	SVC_POOL_AUTO = -1,	/* choose one of the others */
4762306a36Sopenharmony_ci	SVC_POOL_GLOBAL,	/* no mapping, just a single global pool
4862306a36Sopenharmony_ci				 * (legacy & UP mode) */
4962306a36Sopenharmony_ci	SVC_POOL_PERCPU,	/* one pool per cpu */
5062306a36Sopenharmony_ci	SVC_POOL_PERNODE	/* one pool per numa node */
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Structure for mapping cpus to pools and vice versa.
5562306a36Sopenharmony_ci * Setup once during sunrpc initialisation.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct svc_pool_map {
5962306a36Sopenharmony_ci	int count;			/* How many svc_servs use us */
6062306a36Sopenharmony_ci	int mode;			/* Note: int not enum to avoid
6162306a36Sopenharmony_ci					 * warnings about "enumeration value
6262306a36Sopenharmony_ci					 * not handled in switch" */
6362306a36Sopenharmony_ci	unsigned int npools;
6462306a36Sopenharmony_ci	unsigned int *pool_to;		/* maps pool id to cpu or node */
6562306a36Sopenharmony_ci	unsigned int *to_pool;		/* maps cpu or node to pool id */
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic struct svc_pool_map svc_pool_map = {
6962306a36Sopenharmony_ci	.mode = SVC_POOL_DEFAULT
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int
7562306a36Sopenharmony_ciparam_set_pool_mode(const char *val, const struct kernel_param *kp)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int *ip = (int *)kp->arg;
7862306a36Sopenharmony_ci	struct svc_pool_map *m = &svc_pool_map;
7962306a36Sopenharmony_ci	int err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	mutex_lock(&svc_pool_map_mutex);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	err = -EBUSY;
8462306a36Sopenharmony_ci	if (m->count)
8562306a36Sopenharmony_ci		goto out;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	err = 0;
8862306a36Sopenharmony_ci	if (!strncmp(val, "auto", 4))
8962306a36Sopenharmony_ci		*ip = SVC_POOL_AUTO;
9062306a36Sopenharmony_ci	else if (!strncmp(val, "global", 6))
9162306a36Sopenharmony_ci		*ip = SVC_POOL_GLOBAL;
9262306a36Sopenharmony_ci	else if (!strncmp(val, "percpu", 6))
9362306a36Sopenharmony_ci		*ip = SVC_POOL_PERCPU;
9462306a36Sopenharmony_ci	else if (!strncmp(val, "pernode", 7))
9562306a36Sopenharmony_ci		*ip = SVC_POOL_PERNODE;
9662306a36Sopenharmony_ci	else
9762306a36Sopenharmony_ci		err = -EINVAL;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciout:
10062306a36Sopenharmony_ci	mutex_unlock(&svc_pool_map_mutex);
10162306a36Sopenharmony_ci	return err;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic int
10562306a36Sopenharmony_ciparam_get_pool_mode(char *buf, const struct kernel_param *kp)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	int *ip = (int *)kp->arg;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	switch (*ip)
11062306a36Sopenharmony_ci	{
11162306a36Sopenharmony_ci	case SVC_POOL_AUTO:
11262306a36Sopenharmony_ci		return sysfs_emit(buf, "auto\n");
11362306a36Sopenharmony_ci	case SVC_POOL_GLOBAL:
11462306a36Sopenharmony_ci		return sysfs_emit(buf, "global\n");
11562306a36Sopenharmony_ci	case SVC_POOL_PERCPU:
11662306a36Sopenharmony_ci		return sysfs_emit(buf, "percpu\n");
11762306a36Sopenharmony_ci	case SVC_POOL_PERNODE:
11862306a36Sopenharmony_ci		return sysfs_emit(buf, "pernode\n");
11962306a36Sopenharmony_ci	default:
12062306a36Sopenharmony_ci		return sysfs_emit(buf, "%d\n", *ip);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cimodule_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode,
12562306a36Sopenharmony_ci		 &svc_pool_map.mode, 0644);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci * Detect best pool mapping mode heuristically,
12962306a36Sopenharmony_ci * according to the machine's topology.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic int
13262306a36Sopenharmony_cisvc_pool_map_choose_mode(void)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	unsigned int node;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (nr_online_nodes > 1) {
13762306a36Sopenharmony_ci		/*
13862306a36Sopenharmony_ci		 * Actually have multiple NUMA nodes,
13962306a36Sopenharmony_ci		 * so split pools on NUMA node boundaries
14062306a36Sopenharmony_ci		 */
14162306a36Sopenharmony_ci		return SVC_POOL_PERNODE;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	node = first_online_node;
14562306a36Sopenharmony_ci	if (nr_cpus_node(node) > 2) {
14662306a36Sopenharmony_ci		/*
14762306a36Sopenharmony_ci		 * Non-trivial SMP, or CONFIG_NUMA on
14862306a36Sopenharmony_ci		 * non-NUMA hardware, e.g. with a generic
14962306a36Sopenharmony_ci		 * x86_64 kernel on Xeons.  In this case we
15062306a36Sopenharmony_ci		 * want to divide the pools on cpu boundaries.
15162306a36Sopenharmony_ci		 */
15262306a36Sopenharmony_ci		return SVC_POOL_PERCPU;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* default: one global pool */
15662306a36Sopenharmony_ci	return SVC_POOL_GLOBAL;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Allocate the to_pool[] and pool_to[] arrays.
16162306a36Sopenharmony_ci * Returns 0 on success or an errno.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cistatic int
16462306a36Sopenharmony_cisvc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
16762306a36Sopenharmony_ci	if (!m->to_pool)
16862306a36Sopenharmony_ci		goto fail;
16962306a36Sopenharmony_ci	m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
17062306a36Sopenharmony_ci	if (!m->pool_to)
17162306a36Sopenharmony_ci		goto fail_free;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cifail_free:
17662306a36Sopenharmony_ci	kfree(m->to_pool);
17762306a36Sopenharmony_ci	m->to_pool = NULL;
17862306a36Sopenharmony_cifail:
17962306a36Sopenharmony_ci	return -ENOMEM;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/*
18362306a36Sopenharmony_ci * Initialise the pool map for SVC_POOL_PERCPU mode.
18462306a36Sopenharmony_ci * Returns number of pools or <0 on error.
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic int
18762306a36Sopenharmony_cisvc_pool_map_init_percpu(struct svc_pool_map *m)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	unsigned int maxpools = nr_cpu_ids;
19062306a36Sopenharmony_ci	unsigned int pidx = 0;
19162306a36Sopenharmony_ci	unsigned int cpu;
19262306a36Sopenharmony_ci	int err;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	err = svc_pool_map_alloc_arrays(m, maxpools);
19562306a36Sopenharmony_ci	if (err)
19662306a36Sopenharmony_ci		return err;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
19962306a36Sopenharmony_ci		BUG_ON(pidx >= maxpools);
20062306a36Sopenharmony_ci		m->to_pool[cpu] = pidx;
20162306a36Sopenharmony_ci		m->pool_to[pidx] = cpu;
20262306a36Sopenharmony_ci		pidx++;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci	/* cpus brought online later all get mapped to pool0, sorry */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return pidx;
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/*
21162306a36Sopenharmony_ci * Initialise the pool map for SVC_POOL_PERNODE mode.
21262306a36Sopenharmony_ci * Returns number of pools or <0 on error.
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_cistatic int
21562306a36Sopenharmony_cisvc_pool_map_init_pernode(struct svc_pool_map *m)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	unsigned int maxpools = nr_node_ids;
21862306a36Sopenharmony_ci	unsigned int pidx = 0;
21962306a36Sopenharmony_ci	unsigned int node;
22062306a36Sopenharmony_ci	int err;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	err = svc_pool_map_alloc_arrays(m, maxpools);
22362306a36Sopenharmony_ci	if (err)
22462306a36Sopenharmony_ci		return err;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for_each_node_with_cpus(node) {
22762306a36Sopenharmony_ci		/* some architectures (e.g. SN2) have cpuless nodes */
22862306a36Sopenharmony_ci		BUG_ON(pidx > maxpools);
22962306a36Sopenharmony_ci		m->to_pool[node] = pidx;
23062306a36Sopenharmony_ci		m->pool_to[pidx] = node;
23162306a36Sopenharmony_ci		pidx++;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	/* nodes brought online later all get mapped to pool0, sorry */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return pidx;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/*
24062306a36Sopenharmony_ci * Add a reference to the global map of cpus to pools (and
24162306a36Sopenharmony_ci * vice versa) if pools are in use.
24262306a36Sopenharmony_ci * Initialise the map if we're the first user.
24362306a36Sopenharmony_ci * Returns the number of pools. If this is '1', no reference
24462306a36Sopenharmony_ci * was taken.
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic unsigned int
24762306a36Sopenharmony_cisvc_pool_map_get(void)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct svc_pool_map *m = &svc_pool_map;
25062306a36Sopenharmony_ci	int npools = -1;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	mutex_lock(&svc_pool_map_mutex);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (m->count++) {
25562306a36Sopenharmony_ci		mutex_unlock(&svc_pool_map_mutex);
25662306a36Sopenharmony_ci		WARN_ON_ONCE(m->npools <= 1);
25762306a36Sopenharmony_ci		return m->npools;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (m->mode == SVC_POOL_AUTO)
26162306a36Sopenharmony_ci		m->mode = svc_pool_map_choose_mode();
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	switch (m->mode) {
26462306a36Sopenharmony_ci	case SVC_POOL_PERCPU:
26562306a36Sopenharmony_ci		npools = svc_pool_map_init_percpu(m);
26662306a36Sopenharmony_ci		break;
26762306a36Sopenharmony_ci	case SVC_POOL_PERNODE:
26862306a36Sopenharmony_ci		npools = svc_pool_map_init_pernode(m);
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (npools <= 0) {
27362306a36Sopenharmony_ci		/* default, or memory allocation failure */
27462306a36Sopenharmony_ci		npools = 1;
27562306a36Sopenharmony_ci		m->mode = SVC_POOL_GLOBAL;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci	m->npools = npools;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (npools == 1)
28062306a36Sopenharmony_ci		/* service is unpooled, so doesn't hold a reference */
28162306a36Sopenharmony_ci		m->count--;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	mutex_unlock(&svc_pool_map_mutex);
28462306a36Sopenharmony_ci	return npools;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/*
28862306a36Sopenharmony_ci * Drop a reference to the global map of cpus to pools, if
28962306a36Sopenharmony_ci * pools were in use, i.e. if npools > 1.
29062306a36Sopenharmony_ci * When the last reference is dropped, the map data is
29162306a36Sopenharmony_ci * freed; this allows the sysadmin to change the pool
29262306a36Sopenharmony_ci * mode using the pool_mode module option without
29362306a36Sopenharmony_ci * rebooting or re-loading sunrpc.ko.
29462306a36Sopenharmony_ci */
29562306a36Sopenharmony_cistatic void
29662306a36Sopenharmony_cisvc_pool_map_put(int npools)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct svc_pool_map *m = &svc_pool_map;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (npools <= 1)
30162306a36Sopenharmony_ci		return;
30262306a36Sopenharmony_ci	mutex_lock(&svc_pool_map_mutex);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!--m->count) {
30562306a36Sopenharmony_ci		kfree(m->to_pool);
30662306a36Sopenharmony_ci		m->to_pool = NULL;
30762306a36Sopenharmony_ci		kfree(m->pool_to);
30862306a36Sopenharmony_ci		m->pool_to = NULL;
30962306a36Sopenharmony_ci		m->npools = 0;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	mutex_unlock(&svc_pool_map_mutex);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int svc_pool_map_get_node(unsigned int pidx)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	const struct svc_pool_map *m = &svc_pool_map;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (m->count) {
32062306a36Sopenharmony_ci		if (m->mode == SVC_POOL_PERCPU)
32162306a36Sopenharmony_ci			return cpu_to_node(m->pool_to[pidx]);
32262306a36Sopenharmony_ci		if (m->mode == SVC_POOL_PERNODE)
32362306a36Sopenharmony_ci			return m->pool_to[pidx];
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci	return NUMA_NO_NODE;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci/*
32862306a36Sopenharmony_ci * Set the given thread's cpus_allowed mask so that it
32962306a36Sopenharmony_ci * will only run on cpus in the given pool.
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_cistatic inline void
33262306a36Sopenharmony_cisvc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct svc_pool_map *m = &svc_pool_map;
33562306a36Sopenharmony_ci	unsigned int node = m->pool_to[pidx];
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * The caller checks for sv_nrpools > 1, which
33962306a36Sopenharmony_ci	 * implies that we've been initialized.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	WARN_ON_ONCE(m->count == 0);
34262306a36Sopenharmony_ci	if (m->count == 0)
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	switch (m->mode) {
34662306a36Sopenharmony_ci	case SVC_POOL_PERCPU:
34762306a36Sopenharmony_ci	{
34862306a36Sopenharmony_ci		set_cpus_allowed_ptr(task, cpumask_of(node));
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	case SVC_POOL_PERNODE:
35262306a36Sopenharmony_ci	{
35362306a36Sopenharmony_ci		set_cpus_allowed_ptr(task, cpumask_of_node(node));
35462306a36Sopenharmony_ci		break;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/**
36062306a36Sopenharmony_ci * svc_pool_for_cpu - Select pool to run a thread on this cpu
36162306a36Sopenharmony_ci * @serv: An RPC service
36262306a36Sopenharmony_ci *
36362306a36Sopenharmony_ci * Use the active CPU and the svc_pool_map's mode setting to
36462306a36Sopenharmony_ci * select the svc thread pool to use. Once initialized, the
36562306a36Sopenharmony_ci * svc_pool_map does not change.
36662306a36Sopenharmony_ci *
36762306a36Sopenharmony_ci * Return value:
36862306a36Sopenharmony_ci *   A pointer to an svc_pool
36962306a36Sopenharmony_ci */
37062306a36Sopenharmony_cistruct svc_pool *svc_pool_for_cpu(struct svc_serv *serv)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct svc_pool_map *m = &svc_pool_map;
37362306a36Sopenharmony_ci	int cpu = raw_smp_processor_id();
37462306a36Sopenharmony_ci	unsigned int pidx = 0;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (serv->sv_nrpools <= 1)
37762306a36Sopenharmony_ci		return serv->sv_pools;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	switch (m->mode) {
38062306a36Sopenharmony_ci	case SVC_POOL_PERCPU:
38162306a36Sopenharmony_ci		pidx = m->to_pool[cpu];
38262306a36Sopenharmony_ci		break;
38362306a36Sopenharmony_ci	case SVC_POOL_PERNODE:
38462306a36Sopenharmony_ci		pidx = m->to_pool[cpu_to_node(cpu)];
38562306a36Sopenharmony_ci		break;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return &serv->sv_pools[pidx % serv->sv_nrpools];
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ciint svc_rpcb_setup(struct svc_serv *serv, struct net *net)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	int err;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	err = rpcb_create_local(net);
39662306a36Sopenharmony_ci	if (err)
39762306a36Sopenharmony_ci		return err;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Remove any stale portmap registrations */
40062306a36Sopenharmony_ci	svc_unregister(serv, net);
40162306a36Sopenharmony_ci	return 0;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rpcb_setup);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_civoid svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	svc_unregister(serv, net);
40862306a36Sopenharmony_ci	rpcb_put_local(net);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic int svc_uses_rpcbind(struct svc_serv *serv)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct svc_program	*progp;
41562306a36Sopenharmony_ci	unsigned int		i;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
41862306a36Sopenharmony_ci		for (i = 0; i < progp->pg_nvers; i++) {
41962306a36Sopenharmony_ci			if (progp->pg_vers[i] == NULL)
42062306a36Sopenharmony_ci				continue;
42162306a36Sopenharmony_ci			if (!progp->pg_vers[i]->vs_hidden)
42262306a36Sopenharmony_ci				return 1;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return 0;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ciint svc_bind(struct svc_serv *serv, struct net *net)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	if (!svc_uses_rpcbind(serv))
43262306a36Sopenharmony_ci		return 0;
43362306a36Sopenharmony_ci	return svc_rpcb_setup(serv, net);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_bind);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
43862306a36Sopenharmony_cistatic void
43962306a36Sopenharmony_ci__svc_init_bc(struct svc_serv *serv)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	INIT_LIST_HEAD(&serv->sv_cb_list);
44262306a36Sopenharmony_ci	spin_lock_init(&serv->sv_cb_lock);
44362306a36Sopenharmony_ci	init_waitqueue_head(&serv->sv_cb_waitq);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci#else
44662306a36Sopenharmony_cistatic void
44762306a36Sopenharmony_ci__svc_init_bc(struct svc_serv *serv)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci#endif
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/*
45362306a36Sopenharmony_ci * Create an RPC service
45462306a36Sopenharmony_ci */
45562306a36Sopenharmony_cistatic struct svc_serv *
45662306a36Sopenharmony_ci__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
45762306a36Sopenharmony_ci	     int (*threadfn)(void *data))
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct svc_serv	*serv;
46062306a36Sopenharmony_ci	unsigned int vers;
46162306a36Sopenharmony_ci	unsigned int xdrsize;
46262306a36Sopenharmony_ci	unsigned int i;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
46562306a36Sopenharmony_ci		return NULL;
46662306a36Sopenharmony_ci	serv->sv_name      = prog->pg_name;
46762306a36Sopenharmony_ci	serv->sv_program   = prog;
46862306a36Sopenharmony_ci	kref_init(&serv->sv_refcnt);
46962306a36Sopenharmony_ci	serv->sv_stats     = prog->pg_stats;
47062306a36Sopenharmony_ci	if (bufsize > RPCSVC_MAXPAYLOAD)
47162306a36Sopenharmony_ci		bufsize = RPCSVC_MAXPAYLOAD;
47262306a36Sopenharmony_ci	serv->sv_max_payload = bufsize? bufsize : 4096;
47362306a36Sopenharmony_ci	serv->sv_max_mesg  = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
47462306a36Sopenharmony_ci	serv->sv_threadfn = threadfn;
47562306a36Sopenharmony_ci	xdrsize = 0;
47662306a36Sopenharmony_ci	while (prog) {
47762306a36Sopenharmony_ci		prog->pg_lovers = prog->pg_nvers-1;
47862306a36Sopenharmony_ci		for (vers=0; vers<prog->pg_nvers ; vers++)
47962306a36Sopenharmony_ci			if (prog->pg_vers[vers]) {
48062306a36Sopenharmony_ci				prog->pg_hivers = vers;
48162306a36Sopenharmony_ci				if (prog->pg_lovers > vers)
48262306a36Sopenharmony_ci					prog->pg_lovers = vers;
48362306a36Sopenharmony_ci				if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
48462306a36Sopenharmony_ci					xdrsize = prog->pg_vers[vers]->vs_xdrsize;
48562306a36Sopenharmony_ci			}
48662306a36Sopenharmony_ci		prog = prog->pg_next;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	serv->sv_xdrsize   = xdrsize;
48962306a36Sopenharmony_ci	INIT_LIST_HEAD(&serv->sv_tempsocks);
49062306a36Sopenharmony_ci	INIT_LIST_HEAD(&serv->sv_permsocks);
49162306a36Sopenharmony_ci	timer_setup(&serv->sv_temptimer, NULL, 0);
49262306a36Sopenharmony_ci	spin_lock_init(&serv->sv_lock);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	__svc_init_bc(serv);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	serv->sv_nrpools = npools;
49762306a36Sopenharmony_ci	serv->sv_pools =
49862306a36Sopenharmony_ci		kcalloc(serv->sv_nrpools, sizeof(struct svc_pool),
49962306a36Sopenharmony_ci			GFP_KERNEL);
50062306a36Sopenharmony_ci	if (!serv->sv_pools) {
50162306a36Sopenharmony_ci		kfree(serv);
50262306a36Sopenharmony_ci		return NULL;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	for (i = 0; i < serv->sv_nrpools; i++) {
50662306a36Sopenharmony_ci		struct svc_pool *pool = &serv->sv_pools[i];
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		dprintk("svc: initialising pool %u for %s\n",
50962306a36Sopenharmony_ci				i, serv->sv_name);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		pool->sp_id = i;
51262306a36Sopenharmony_ci		INIT_LIST_HEAD(&pool->sp_sockets);
51362306a36Sopenharmony_ci		INIT_LIST_HEAD(&pool->sp_all_threads);
51462306a36Sopenharmony_ci		spin_lock_init(&pool->sp_lock);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		percpu_counter_init(&pool->sp_messages_arrived, 0, GFP_KERNEL);
51762306a36Sopenharmony_ci		percpu_counter_init(&pool->sp_sockets_queued, 0, GFP_KERNEL);
51862306a36Sopenharmony_ci		percpu_counter_init(&pool->sp_threads_woken, 0, GFP_KERNEL);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return serv;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/**
52562306a36Sopenharmony_ci * svc_create - Create an RPC service
52662306a36Sopenharmony_ci * @prog: the RPC program the new service will handle
52762306a36Sopenharmony_ci * @bufsize: maximum message size for @prog
52862306a36Sopenharmony_ci * @threadfn: a function to service RPC requests for @prog
52962306a36Sopenharmony_ci *
53062306a36Sopenharmony_ci * Returns an instantiated struct svc_serv object or NULL.
53162306a36Sopenharmony_ci */
53262306a36Sopenharmony_cistruct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize,
53362306a36Sopenharmony_ci			    int (*threadfn)(void *data))
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	return __svc_create(prog, bufsize, 1, threadfn);
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_create);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/**
54062306a36Sopenharmony_ci * svc_create_pooled - Create an RPC service with pooled threads
54162306a36Sopenharmony_ci * @prog: the RPC program the new service will handle
54262306a36Sopenharmony_ci * @bufsize: maximum message size for @prog
54362306a36Sopenharmony_ci * @threadfn: a function to service RPC requests for @prog
54462306a36Sopenharmony_ci *
54562306a36Sopenharmony_ci * Returns an instantiated struct svc_serv object or NULL.
54662306a36Sopenharmony_ci */
54762306a36Sopenharmony_cistruct svc_serv *svc_create_pooled(struct svc_program *prog,
54862306a36Sopenharmony_ci				   unsigned int bufsize,
54962306a36Sopenharmony_ci				   int (*threadfn)(void *data))
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct svc_serv *serv;
55262306a36Sopenharmony_ci	unsigned int npools = svc_pool_map_get();
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	serv = __svc_create(prog, bufsize, npools, threadfn);
55562306a36Sopenharmony_ci	if (!serv)
55662306a36Sopenharmony_ci		goto out_err;
55762306a36Sopenharmony_ci	return serv;
55862306a36Sopenharmony_ciout_err:
55962306a36Sopenharmony_ci	svc_pool_map_put(npools);
56062306a36Sopenharmony_ci	return NULL;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_create_pooled);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/*
56562306a36Sopenharmony_ci * Destroy an RPC service. Should be called with appropriate locking to
56662306a36Sopenharmony_ci * protect sv_permsocks and sv_tempsocks.
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_civoid
56962306a36Sopenharmony_cisvc_destroy(struct kref *ref)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	struct svc_serv *serv = container_of(ref, struct svc_serv, sv_refcnt);
57262306a36Sopenharmony_ci	unsigned int i;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name);
57562306a36Sopenharmony_ci	timer_shutdown_sync(&serv->sv_temptimer);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/*
57862306a36Sopenharmony_ci	 * The last user is gone and thus all sockets have to be destroyed to
57962306a36Sopenharmony_ci	 * the point. Check this.
58062306a36Sopenharmony_ci	 */
58162306a36Sopenharmony_ci	BUG_ON(!list_empty(&serv->sv_permsocks));
58262306a36Sopenharmony_ci	BUG_ON(!list_empty(&serv->sv_tempsocks));
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	cache_clean_deferred(serv);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	svc_pool_map_put(serv->sv_nrpools);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	for (i = 0; i < serv->sv_nrpools; i++) {
58962306a36Sopenharmony_ci		struct svc_pool *pool = &serv->sv_pools[i];
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		percpu_counter_destroy(&pool->sp_messages_arrived);
59262306a36Sopenharmony_ci		percpu_counter_destroy(&pool->sp_sockets_queued);
59362306a36Sopenharmony_ci		percpu_counter_destroy(&pool->sp_threads_woken);
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci	kfree(serv->sv_pools);
59662306a36Sopenharmony_ci	kfree(serv);
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_destroy);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic bool
60162306a36Sopenharmony_cisvc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	unsigned long pages, ret;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* bc_xprt uses fore channel allocated buffers */
60662306a36Sopenharmony_ci	if (svc_is_backchannel(rqstp))
60762306a36Sopenharmony_ci		return true;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
61062306a36Sopenharmony_ci				       * We assume one is at most one page
61162306a36Sopenharmony_ci				       */
61262306a36Sopenharmony_ci	WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
61362306a36Sopenharmony_ci	if (pages > RPCSVC_MAXPAGES)
61462306a36Sopenharmony_ci		pages = RPCSVC_MAXPAGES;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	ret = alloc_pages_bulk_array_node(GFP_KERNEL, node, pages,
61762306a36Sopenharmony_ci					  rqstp->rq_pages);
61862306a36Sopenharmony_ci	return ret == pages;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci/*
62262306a36Sopenharmony_ci * Release an RPC server buffer
62362306a36Sopenharmony_ci */
62462306a36Sopenharmony_cistatic void
62562306a36Sopenharmony_cisvc_release_buffer(struct svc_rqst *rqstp)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	unsigned int i;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
63062306a36Sopenharmony_ci		if (rqstp->rq_pages[i])
63162306a36Sopenharmony_ci			put_page(rqstp->rq_pages[i]);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistruct svc_rqst *
63562306a36Sopenharmony_cisvc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct svc_rqst	*rqstp;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node);
64062306a36Sopenharmony_ci	if (!rqstp)
64162306a36Sopenharmony_ci		return rqstp;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	folio_batch_init(&rqstp->rq_fbatch);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	__set_bit(RQ_BUSY, &rqstp->rq_flags);
64662306a36Sopenharmony_ci	rqstp->rq_server = serv;
64762306a36Sopenharmony_ci	rqstp->rq_pool = pool;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0);
65062306a36Sopenharmony_ci	if (!rqstp->rq_scratch_page)
65162306a36Sopenharmony_ci		goto out_enomem;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
65462306a36Sopenharmony_ci	if (!rqstp->rq_argp)
65562306a36Sopenharmony_ci		goto out_enomem;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
65862306a36Sopenharmony_ci	if (!rqstp->rq_resp)
65962306a36Sopenharmony_ci		goto out_enomem;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
66262306a36Sopenharmony_ci		goto out_enomem;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return rqstp;
66562306a36Sopenharmony_ciout_enomem:
66662306a36Sopenharmony_ci	svc_rqst_free(rqstp);
66762306a36Sopenharmony_ci	return NULL;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rqst_alloc);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic struct svc_rqst *
67262306a36Sopenharmony_cisvc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct svc_rqst	*rqstp;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	rqstp = svc_rqst_alloc(serv, pool, node);
67762306a36Sopenharmony_ci	if (!rqstp)
67862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	svc_get(serv);
68162306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
68262306a36Sopenharmony_ci	serv->sv_nrthreads += 1;
68362306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	spin_lock_bh(&pool->sp_lock);
68662306a36Sopenharmony_ci	pool->sp_nrthreads++;
68762306a36Sopenharmony_ci	list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads);
68862306a36Sopenharmony_ci	spin_unlock_bh(&pool->sp_lock);
68962306a36Sopenharmony_ci	return rqstp;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci/**
69362306a36Sopenharmony_ci * svc_pool_wake_idle_thread - Awaken an idle thread in @pool
69462306a36Sopenharmony_ci * @pool: service thread pool
69562306a36Sopenharmony_ci *
69662306a36Sopenharmony_ci * Can be called from soft IRQ or process context. Finding an idle
69762306a36Sopenharmony_ci * service thread and marking it BUSY is atomic with respect to
69862306a36Sopenharmony_ci * other calls to svc_pool_wake_idle_thread().
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_civoid svc_pool_wake_idle_thread(struct svc_pool *pool)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	struct svc_rqst	*rqstp;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	rcu_read_lock();
70662306a36Sopenharmony_ci	list_for_each_entry_rcu(rqstp, &pool->sp_all_threads, rq_all) {
70762306a36Sopenharmony_ci		if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags))
70862306a36Sopenharmony_ci			continue;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		WRITE_ONCE(rqstp->rq_qtime, ktime_get());
71162306a36Sopenharmony_ci		wake_up_process(rqstp->rq_task);
71262306a36Sopenharmony_ci		rcu_read_unlock();
71362306a36Sopenharmony_ci		percpu_counter_inc(&pool->sp_threads_woken);
71462306a36Sopenharmony_ci		trace_svc_wake_up(rqstp->rq_task->pid);
71562306a36Sopenharmony_ci		return;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci	rcu_read_unlock();
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	set_bit(SP_CONGESTED, &pool->sp_flags);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic struct svc_pool *
72362306a36Sopenharmony_cisvc_pool_next(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	return pool ? pool : &serv->sv_pools[(*state)++ % serv->sv_nrpools];
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic struct task_struct *
72962306a36Sopenharmony_cisvc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	unsigned int i;
73262306a36Sopenharmony_ci	struct task_struct *task = NULL;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (pool != NULL) {
73562306a36Sopenharmony_ci		spin_lock_bh(&pool->sp_lock);
73662306a36Sopenharmony_ci	} else {
73762306a36Sopenharmony_ci		for (i = 0; i < serv->sv_nrpools; i++) {
73862306a36Sopenharmony_ci			pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
73962306a36Sopenharmony_ci			spin_lock_bh(&pool->sp_lock);
74062306a36Sopenharmony_ci			if (!list_empty(&pool->sp_all_threads))
74162306a36Sopenharmony_ci				goto found_pool;
74262306a36Sopenharmony_ci			spin_unlock_bh(&pool->sp_lock);
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci		return NULL;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cifound_pool:
74862306a36Sopenharmony_ci	if (!list_empty(&pool->sp_all_threads)) {
74962306a36Sopenharmony_ci		struct svc_rqst *rqstp;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
75262306a36Sopenharmony_ci		set_bit(RQ_VICTIM, &rqstp->rq_flags);
75362306a36Sopenharmony_ci		list_del_rcu(&rqstp->rq_all);
75462306a36Sopenharmony_ci		task = rqstp->rq_task;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	spin_unlock_bh(&pool->sp_lock);
75762306a36Sopenharmony_ci	return task;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic int
76162306a36Sopenharmony_cisvc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct svc_rqst	*rqstp;
76462306a36Sopenharmony_ci	struct task_struct *task;
76562306a36Sopenharmony_ci	struct svc_pool *chosen_pool;
76662306a36Sopenharmony_ci	unsigned int state = serv->sv_nrthreads-1;
76762306a36Sopenharmony_ci	int node;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	do {
77062306a36Sopenharmony_ci		nrservs--;
77162306a36Sopenharmony_ci		chosen_pool = svc_pool_next(serv, pool, &state);
77262306a36Sopenharmony_ci		node = svc_pool_map_get_node(chosen_pool->sp_id);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci		rqstp = svc_prepare_thread(serv, chosen_pool, node);
77562306a36Sopenharmony_ci		if (IS_ERR(rqstp))
77662306a36Sopenharmony_ci			return PTR_ERR(rqstp);
77762306a36Sopenharmony_ci		task = kthread_create_on_node(serv->sv_threadfn, rqstp,
77862306a36Sopenharmony_ci					      node, "%s", serv->sv_name);
77962306a36Sopenharmony_ci		if (IS_ERR(task)) {
78062306a36Sopenharmony_ci			svc_exit_thread(rqstp);
78162306a36Sopenharmony_ci			return PTR_ERR(task);
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		rqstp->rq_task = task;
78562306a36Sopenharmony_ci		if (serv->sv_nrpools > 1)
78662306a36Sopenharmony_ci			svc_pool_map_set_cpumask(task, chosen_pool->sp_id);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		svc_sock_update_bufs(serv);
78962306a36Sopenharmony_ci		wake_up_process(task);
79062306a36Sopenharmony_ci	} while (nrservs > 0);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	return 0;
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic int
79662306a36Sopenharmony_cisvc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	struct svc_rqst	*rqstp;
79962306a36Sopenharmony_ci	struct task_struct *task;
80062306a36Sopenharmony_ci	unsigned int state = serv->sv_nrthreads-1;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	do {
80362306a36Sopenharmony_ci		task = svc_pool_victim(serv, pool, &state);
80462306a36Sopenharmony_ci		if (task == NULL)
80562306a36Sopenharmony_ci			break;
80662306a36Sopenharmony_ci		rqstp = kthread_data(task);
80762306a36Sopenharmony_ci		/* Did we lose a race to svo_function threadfn? */
80862306a36Sopenharmony_ci		if (kthread_stop(task) == -EINTR)
80962306a36Sopenharmony_ci			svc_exit_thread(rqstp);
81062306a36Sopenharmony_ci		nrservs++;
81162306a36Sopenharmony_ci	} while (nrservs < 0);
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci/**
81662306a36Sopenharmony_ci * svc_set_num_threads - adjust number of threads per RPC service
81762306a36Sopenharmony_ci * @serv: RPC service to adjust
81862306a36Sopenharmony_ci * @pool: Specific pool from which to choose threads, or NULL
81962306a36Sopenharmony_ci * @nrservs: New number of threads for @serv (0 or less means kill all threads)
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * Create or destroy threads to make the number of threads for @serv the
82262306a36Sopenharmony_ci * given number. If @pool is non-NULL, change only threads in that pool;
82362306a36Sopenharmony_ci * otherwise, round-robin between all pools for @serv. @serv's
82462306a36Sopenharmony_ci * sv_nrthreads is adjusted for each thread created or destroyed.
82562306a36Sopenharmony_ci *
82662306a36Sopenharmony_ci * Caller must ensure mutual exclusion between this and server startup or
82762306a36Sopenharmony_ci * shutdown.
82862306a36Sopenharmony_ci *
82962306a36Sopenharmony_ci * Returns zero on success or a negative errno if an error occurred while
83062306a36Sopenharmony_ci * starting a thread.
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_ciint
83362306a36Sopenharmony_cisvc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	if (pool == NULL) {
83662306a36Sopenharmony_ci		nrservs -= serv->sv_nrthreads;
83762306a36Sopenharmony_ci	} else {
83862306a36Sopenharmony_ci		spin_lock_bh(&pool->sp_lock);
83962306a36Sopenharmony_ci		nrservs -= pool->sp_nrthreads;
84062306a36Sopenharmony_ci		spin_unlock_bh(&pool->sp_lock);
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (nrservs > 0)
84462306a36Sopenharmony_ci		return svc_start_kthreads(serv, pool, nrservs);
84562306a36Sopenharmony_ci	if (nrservs < 0)
84662306a36Sopenharmony_ci		return svc_stop_kthreads(serv, pool, nrservs);
84762306a36Sopenharmony_ci	return 0;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_set_num_threads);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci/**
85262306a36Sopenharmony_ci * svc_rqst_replace_page - Replace one page in rq_pages[]
85362306a36Sopenharmony_ci * @rqstp: svc_rqst with pages to replace
85462306a36Sopenharmony_ci * @page: replacement page
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * When replacing a page in rq_pages, batch the release of the
85762306a36Sopenharmony_ci * replaced pages to avoid hammering the page allocator.
85862306a36Sopenharmony_ci *
85962306a36Sopenharmony_ci * Return values:
86062306a36Sopenharmony_ci *   %true: page replaced
86162306a36Sopenharmony_ci *   %false: array bounds checking failed
86262306a36Sopenharmony_ci */
86362306a36Sopenharmony_cibool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct page **begin = rqstp->rq_pages;
86662306a36Sopenharmony_ci	struct page **end = &rqstp->rq_pages[RPCSVC_MAXPAGES];
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) {
86962306a36Sopenharmony_ci		trace_svc_replace_page_err(rqstp);
87062306a36Sopenharmony_ci		return false;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (*rqstp->rq_next_page) {
87462306a36Sopenharmony_ci		if (!folio_batch_add(&rqstp->rq_fbatch,
87562306a36Sopenharmony_ci				page_folio(*rqstp->rq_next_page)))
87662306a36Sopenharmony_ci			__folio_batch_release(&rqstp->rq_fbatch);
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	get_page(page);
88062306a36Sopenharmony_ci	*(rqstp->rq_next_page++) = page;
88162306a36Sopenharmony_ci	return true;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rqst_replace_page);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/**
88662306a36Sopenharmony_ci * svc_rqst_release_pages - Release Reply buffer pages
88762306a36Sopenharmony_ci * @rqstp: RPC transaction context
88862306a36Sopenharmony_ci *
88962306a36Sopenharmony_ci * Release response pages that might still be in flight after
89062306a36Sopenharmony_ci * svc_send, and any spliced filesystem-owned pages.
89162306a36Sopenharmony_ci */
89262306a36Sopenharmony_civoid svc_rqst_release_pages(struct svc_rqst *rqstp)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	int i, count = rqstp->rq_next_page - rqstp->rq_respages;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	if (count) {
89762306a36Sopenharmony_ci		release_pages(rqstp->rq_respages, count);
89862306a36Sopenharmony_ci		for (i = 0; i < count; i++)
89962306a36Sopenharmony_ci			rqstp->rq_respages[i] = NULL;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/*
90462306a36Sopenharmony_ci * Called from a server thread as it's exiting. Caller must hold the "service
90562306a36Sopenharmony_ci * mutex" for the service.
90662306a36Sopenharmony_ci */
90762306a36Sopenharmony_civoid
90862306a36Sopenharmony_cisvc_rqst_free(struct svc_rqst *rqstp)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	folio_batch_release(&rqstp->rq_fbatch);
91162306a36Sopenharmony_ci	svc_release_buffer(rqstp);
91262306a36Sopenharmony_ci	if (rqstp->rq_scratch_page)
91362306a36Sopenharmony_ci		put_page(rqstp->rq_scratch_page);
91462306a36Sopenharmony_ci	kfree(rqstp->rq_resp);
91562306a36Sopenharmony_ci	kfree(rqstp->rq_argp);
91662306a36Sopenharmony_ci	kfree(rqstp->rq_auth_data);
91762306a36Sopenharmony_ci	kfree_rcu(rqstp, rq_rcu_head);
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rqst_free);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_civoid
92262306a36Sopenharmony_cisvc_exit_thread(struct svc_rqst *rqstp)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	struct svc_serv	*serv = rqstp->rq_server;
92562306a36Sopenharmony_ci	struct svc_pool	*pool = rqstp->rq_pool;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	spin_lock_bh(&pool->sp_lock);
92862306a36Sopenharmony_ci	pool->sp_nrthreads--;
92962306a36Sopenharmony_ci	if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags))
93062306a36Sopenharmony_ci		list_del_rcu(&rqstp->rq_all);
93162306a36Sopenharmony_ci	spin_unlock_bh(&pool->sp_lock);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	spin_lock_bh(&serv->sv_lock);
93462306a36Sopenharmony_ci	serv->sv_nrthreads -= 1;
93562306a36Sopenharmony_ci	spin_unlock_bh(&serv->sv_lock);
93662306a36Sopenharmony_ci	svc_sock_update_bufs(serv);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	svc_rqst_free(rqstp);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	svc_put(serv);
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_exit_thread);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci/*
94562306a36Sopenharmony_ci * Register an "inet" protocol family netid with the local
94662306a36Sopenharmony_ci * rpcbind daemon via an rpcbind v4 SET request.
94762306a36Sopenharmony_ci *
94862306a36Sopenharmony_ci * No netconfig infrastructure is available in the kernel, so
94962306a36Sopenharmony_ci * we map IP_ protocol numbers to netids by hand.
95062306a36Sopenharmony_ci *
95162306a36Sopenharmony_ci * Returns zero on success; a negative errno value is returned
95262306a36Sopenharmony_ci * if any error occurs.
95362306a36Sopenharmony_ci */
95462306a36Sopenharmony_cistatic int __svc_rpcb_register4(struct net *net, const u32 program,
95562306a36Sopenharmony_ci				const u32 version,
95662306a36Sopenharmony_ci				const unsigned short protocol,
95762306a36Sopenharmony_ci				const unsigned short port)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	const struct sockaddr_in sin = {
96062306a36Sopenharmony_ci		.sin_family		= AF_INET,
96162306a36Sopenharmony_ci		.sin_addr.s_addr	= htonl(INADDR_ANY),
96262306a36Sopenharmony_ci		.sin_port		= htons(port),
96362306a36Sopenharmony_ci	};
96462306a36Sopenharmony_ci	const char *netid;
96562306a36Sopenharmony_ci	int error;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	switch (protocol) {
96862306a36Sopenharmony_ci	case IPPROTO_UDP:
96962306a36Sopenharmony_ci		netid = RPCBIND_NETID_UDP;
97062306a36Sopenharmony_ci		break;
97162306a36Sopenharmony_ci	case IPPROTO_TCP:
97262306a36Sopenharmony_ci		netid = RPCBIND_NETID_TCP;
97362306a36Sopenharmony_ci		break;
97462306a36Sopenharmony_ci	default:
97562306a36Sopenharmony_ci		return -ENOPROTOOPT;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	error = rpcb_v4_register(net, program, version,
97962306a36Sopenharmony_ci					(const struct sockaddr *)&sin, netid);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/*
98262306a36Sopenharmony_ci	 * User space didn't support rpcbind v4, so retry this
98362306a36Sopenharmony_ci	 * registration request with the legacy rpcbind v2 protocol.
98462306a36Sopenharmony_ci	 */
98562306a36Sopenharmony_ci	if (error == -EPROTONOSUPPORT)
98662306a36Sopenharmony_ci		error = rpcb_register(net, program, version, protocol, port);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return error;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
99262306a36Sopenharmony_ci/*
99362306a36Sopenharmony_ci * Register an "inet6" protocol family netid with the local
99462306a36Sopenharmony_ci * rpcbind daemon via an rpcbind v4 SET request.
99562306a36Sopenharmony_ci *
99662306a36Sopenharmony_ci * No netconfig infrastructure is available in the kernel, so
99762306a36Sopenharmony_ci * we map IP_ protocol numbers to netids by hand.
99862306a36Sopenharmony_ci *
99962306a36Sopenharmony_ci * Returns zero on success; a negative errno value is returned
100062306a36Sopenharmony_ci * if any error occurs.
100162306a36Sopenharmony_ci */
100262306a36Sopenharmony_cistatic int __svc_rpcb_register6(struct net *net, const u32 program,
100362306a36Sopenharmony_ci				const u32 version,
100462306a36Sopenharmony_ci				const unsigned short protocol,
100562306a36Sopenharmony_ci				const unsigned short port)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	const struct sockaddr_in6 sin6 = {
100862306a36Sopenharmony_ci		.sin6_family		= AF_INET6,
100962306a36Sopenharmony_ci		.sin6_addr		= IN6ADDR_ANY_INIT,
101062306a36Sopenharmony_ci		.sin6_port		= htons(port),
101162306a36Sopenharmony_ci	};
101262306a36Sopenharmony_ci	const char *netid;
101362306a36Sopenharmony_ci	int error;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	switch (protocol) {
101662306a36Sopenharmony_ci	case IPPROTO_UDP:
101762306a36Sopenharmony_ci		netid = RPCBIND_NETID_UDP6;
101862306a36Sopenharmony_ci		break;
101962306a36Sopenharmony_ci	case IPPROTO_TCP:
102062306a36Sopenharmony_ci		netid = RPCBIND_NETID_TCP6;
102162306a36Sopenharmony_ci		break;
102262306a36Sopenharmony_ci	default:
102362306a36Sopenharmony_ci		return -ENOPROTOOPT;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	error = rpcb_v4_register(net, program, version,
102762306a36Sopenharmony_ci					(const struct sockaddr *)&sin6, netid);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	/*
103062306a36Sopenharmony_ci	 * User space didn't support rpcbind version 4, so we won't
103162306a36Sopenharmony_ci	 * use a PF_INET6 listener.
103262306a36Sopenharmony_ci	 */
103362306a36Sopenharmony_ci	if (error == -EPROTONOSUPPORT)
103462306a36Sopenharmony_ci		error = -EAFNOSUPPORT;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	return error;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci#endif	/* IS_ENABLED(CONFIG_IPV6) */
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci/*
104162306a36Sopenharmony_ci * Register a kernel RPC service via rpcbind version 4.
104262306a36Sopenharmony_ci *
104362306a36Sopenharmony_ci * Returns zero on success; a negative errno value is returned
104462306a36Sopenharmony_ci * if any error occurs.
104562306a36Sopenharmony_ci */
104662306a36Sopenharmony_cistatic int __svc_register(struct net *net, const char *progname,
104762306a36Sopenharmony_ci			  const u32 program, const u32 version,
104862306a36Sopenharmony_ci			  const int family,
104962306a36Sopenharmony_ci			  const unsigned short protocol,
105062306a36Sopenharmony_ci			  const unsigned short port)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	int error = -EAFNOSUPPORT;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	switch (family) {
105562306a36Sopenharmony_ci	case PF_INET:
105662306a36Sopenharmony_ci		error = __svc_rpcb_register4(net, program, version,
105762306a36Sopenharmony_ci						protocol, port);
105862306a36Sopenharmony_ci		break;
105962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
106062306a36Sopenharmony_ci	case PF_INET6:
106162306a36Sopenharmony_ci		error = __svc_rpcb_register6(net, program, version,
106262306a36Sopenharmony_ci						protocol, port);
106362306a36Sopenharmony_ci#endif
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	trace_svc_register(progname, version, family, protocol, port, error);
106762306a36Sopenharmony_ci	return error;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ciint svc_rpcbind_set_version(struct net *net,
107162306a36Sopenharmony_ci			    const struct svc_program *progp,
107262306a36Sopenharmony_ci			    u32 version, int family,
107362306a36Sopenharmony_ci			    unsigned short proto,
107462306a36Sopenharmony_ci			    unsigned short port)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	return __svc_register(net, progp->pg_name, progp->pg_prog,
107762306a36Sopenharmony_ci				version, family, proto, port);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_rpcbind_set_version);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ciint svc_generic_rpcbind_set(struct net *net,
108362306a36Sopenharmony_ci			    const struct svc_program *progp,
108462306a36Sopenharmony_ci			    u32 version, int family,
108562306a36Sopenharmony_ci			    unsigned short proto,
108662306a36Sopenharmony_ci			    unsigned short port)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	const struct svc_version *vers = progp->pg_vers[version];
108962306a36Sopenharmony_ci	int error;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (vers == NULL)
109262306a36Sopenharmony_ci		return 0;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (vers->vs_hidden) {
109562306a36Sopenharmony_ci		trace_svc_noregister(progp->pg_name, version, proto,
109662306a36Sopenharmony_ci				     port, family, 0);
109762306a36Sopenharmony_ci		return 0;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/*
110162306a36Sopenharmony_ci	 * Don't register a UDP port if we need congestion
110262306a36Sopenharmony_ci	 * control.
110362306a36Sopenharmony_ci	 */
110462306a36Sopenharmony_ci	if (vers->vs_need_cong_ctrl && proto == IPPROTO_UDP)
110562306a36Sopenharmony_ci		return 0;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	error = svc_rpcbind_set_version(net, progp, version,
110862306a36Sopenharmony_ci					family, proto, port);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return (vers->vs_rpcb_optnl) ? 0 : error;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci/**
111562306a36Sopenharmony_ci * svc_register - register an RPC service with the local portmapper
111662306a36Sopenharmony_ci * @serv: svc_serv struct for the service to register
111762306a36Sopenharmony_ci * @net: net namespace for the service to register
111862306a36Sopenharmony_ci * @family: protocol family of service's listener socket
111962306a36Sopenharmony_ci * @proto: transport protocol number to advertise
112062306a36Sopenharmony_ci * @port: port to advertise
112162306a36Sopenharmony_ci *
112262306a36Sopenharmony_ci * Service is registered for any address in the passed-in protocol family
112362306a36Sopenharmony_ci */
112462306a36Sopenharmony_ciint svc_register(const struct svc_serv *serv, struct net *net,
112562306a36Sopenharmony_ci		 const int family, const unsigned short proto,
112662306a36Sopenharmony_ci		 const unsigned short port)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct svc_program	*progp;
112962306a36Sopenharmony_ci	unsigned int		i;
113062306a36Sopenharmony_ci	int			error = 0;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	WARN_ON_ONCE(proto == 0 && port == 0);
113362306a36Sopenharmony_ci	if (proto == 0 && port == 0)
113462306a36Sopenharmony_ci		return -EINVAL;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
113762306a36Sopenharmony_ci		for (i = 0; i < progp->pg_nvers; i++) {
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci			error = progp->pg_rpcbind_set(net, progp, i,
114062306a36Sopenharmony_ci					family, proto, port);
114162306a36Sopenharmony_ci			if (error < 0) {
114262306a36Sopenharmony_ci				printk(KERN_WARNING "svc: failed to register "
114362306a36Sopenharmony_ci					"%sv%u RPC service (errno %d).\n",
114462306a36Sopenharmony_ci					progp->pg_name, i, -error);
114562306a36Sopenharmony_ci				break;
114662306a36Sopenharmony_ci			}
114762306a36Sopenharmony_ci		}
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return error;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci/*
115462306a36Sopenharmony_ci * If user space is running rpcbind, it should take the v4 UNSET
115562306a36Sopenharmony_ci * and clear everything for this [program, version].  If user space
115662306a36Sopenharmony_ci * is running portmap, it will reject the v4 UNSET, but won't have
115762306a36Sopenharmony_ci * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
115862306a36Sopenharmony_ci * in this case to clear all existing entries for [program, version].
115962306a36Sopenharmony_ci */
116062306a36Sopenharmony_cistatic void __svc_unregister(struct net *net, const u32 program, const u32 version,
116162306a36Sopenharmony_ci			     const char *progname)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	int error;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	error = rpcb_v4_register(net, program, version, NULL, "");
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	/*
116862306a36Sopenharmony_ci	 * User space didn't support rpcbind v4, so retry this
116962306a36Sopenharmony_ci	 * request with the legacy rpcbind v2 protocol.
117062306a36Sopenharmony_ci	 */
117162306a36Sopenharmony_ci	if (error == -EPROTONOSUPPORT)
117262306a36Sopenharmony_ci		error = rpcb_register(net, program, version, 0, 0);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	trace_svc_unregister(progname, version, error);
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci/*
117862306a36Sopenharmony_ci * All netids, bind addresses and ports registered for [program, version]
117962306a36Sopenharmony_ci * are removed from the local rpcbind database (if the service is not
118062306a36Sopenharmony_ci * hidden) to make way for a new instance of the service.
118162306a36Sopenharmony_ci *
118262306a36Sopenharmony_ci * The result of unregistration is reported via dprintk for those who want
118362306a36Sopenharmony_ci * verification of the result, but is otherwise not important.
118462306a36Sopenharmony_ci */
118562306a36Sopenharmony_cistatic void svc_unregister(const struct svc_serv *serv, struct net *net)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	struct sighand_struct *sighand;
118862306a36Sopenharmony_ci	struct svc_program *progp;
118962306a36Sopenharmony_ci	unsigned long flags;
119062306a36Sopenharmony_ci	unsigned int i;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	clear_thread_flag(TIF_SIGPENDING);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
119562306a36Sopenharmony_ci		for (i = 0; i < progp->pg_nvers; i++) {
119662306a36Sopenharmony_ci			if (progp->pg_vers[i] == NULL)
119762306a36Sopenharmony_ci				continue;
119862306a36Sopenharmony_ci			if (progp->pg_vers[i]->vs_hidden)
119962306a36Sopenharmony_ci				continue;
120062306a36Sopenharmony_ci			__svc_unregister(net, progp->pg_prog, i, progp->pg_name);
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	rcu_read_lock();
120562306a36Sopenharmony_ci	sighand = rcu_dereference(current->sighand);
120662306a36Sopenharmony_ci	spin_lock_irqsave(&sighand->siglock, flags);
120762306a36Sopenharmony_ci	recalc_sigpending();
120862306a36Sopenharmony_ci	spin_unlock_irqrestore(&sighand->siglock, flags);
120962306a36Sopenharmony_ci	rcu_read_unlock();
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci/*
121362306a36Sopenharmony_ci * dprintk the given error with the address of the client that caused it.
121462306a36Sopenharmony_ci */
121562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
121662306a36Sopenharmony_cistatic __printf(2, 3)
121762306a36Sopenharmony_civoid svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct va_format vaf;
122062306a36Sopenharmony_ci	va_list args;
122162306a36Sopenharmony_ci	char 	buf[RPC_MAX_ADDRBUFLEN];
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	va_start(args, fmt);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	vaf.fmt = fmt;
122662306a36Sopenharmony_ci	vaf.va = &args;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	va_end(args);
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci#else
123362306a36Sopenharmony_cistatic __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
123462306a36Sopenharmony_ci#endif
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci__be32
123762306a36Sopenharmony_cisvc_generic_init_request(struct svc_rqst *rqstp,
123862306a36Sopenharmony_ci		const struct svc_program *progp,
123962306a36Sopenharmony_ci		struct svc_process_info *ret)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	const struct svc_version *versp = NULL;	/* compiler food */
124262306a36Sopenharmony_ci	const struct svc_procedure *procp = NULL;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (rqstp->rq_vers >= progp->pg_nvers )
124562306a36Sopenharmony_ci		goto err_bad_vers;
124662306a36Sopenharmony_ci	versp = progp->pg_vers[rqstp->rq_vers];
124762306a36Sopenharmony_ci	if (!versp)
124862306a36Sopenharmony_ci		goto err_bad_vers;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	/*
125162306a36Sopenharmony_ci	 * Some protocol versions (namely NFSv4) require some form of
125262306a36Sopenharmony_ci	 * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
125362306a36Sopenharmony_ci	 * In other words, UDP is not allowed. We mark those when setting
125462306a36Sopenharmony_ci	 * up the svc_xprt, and verify that here.
125562306a36Sopenharmony_ci	 *
125662306a36Sopenharmony_ci	 * The spec is not very clear about what error should be returned
125762306a36Sopenharmony_ci	 * when someone tries to access a server that is listening on UDP
125862306a36Sopenharmony_ci	 * for lower versions. RPC_PROG_MISMATCH seems to be the closest
125962306a36Sopenharmony_ci	 * fit.
126062306a36Sopenharmony_ci	 */
126162306a36Sopenharmony_ci	if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
126262306a36Sopenharmony_ci	    !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
126362306a36Sopenharmony_ci		goto err_bad_vers;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (rqstp->rq_proc >= versp->vs_nproc)
126662306a36Sopenharmony_ci		goto err_bad_proc;
126762306a36Sopenharmony_ci	rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
126862306a36Sopenharmony_ci	if (!procp)
126962306a36Sopenharmony_ci		goto err_bad_proc;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	/* Initialize storage for argp and resp */
127262306a36Sopenharmony_ci	memset(rqstp->rq_argp, 0, procp->pc_argzero);
127362306a36Sopenharmony_ci	memset(rqstp->rq_resp, 0, procp->pc_ressize);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* Bump per-procedure stats counter */
127662306a36Sopenharmony_ci	this_cpu_inc(versp->vs_count[rqstp->rq_proc]);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	ret->dispatch = versp->vs_dispatch;
127962306a36Sopenharmony_ci	return rpc_success;
128062306a36Sopenharmony_cierr_bad_vers:
128162306a36Sopenharmony_ci	ret->mismatch.lovers = progp->pg_lovers;
128262306a36Sopenharmony_ci	ret->mismatch.hivers = progp->pg_hivers;
128362306a36Sopenharmony_ci	return rpc_prog_mismatch;
128462306a36Sopenharmony_cierr_bad_proc:
128562306a36Sopenharmony_ci	return rpc_proc_unavail;
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_generic_init_request);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci/*
129062306a36Sopenharmony_ci * Common routine for processing the RPC request.
129162306a36Sopenharmony_ci */
129262306a36Sopenharmony_cistatic int
129362306a36Sopenharmony_cisvc_process_common(struct svc_rqst *rqstp)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct xdr_stream	*xdr = &rqstp->rq_res_stream;
129662306a36Sopenharmony_ci	struct svc_program	*progp;
129762306a36Sopenharmony_ci	const struct svc_procedure *procp = NULL;
129862306a36Sopenharmony_ci	struct svc_serv		*serv = rqstp->rq_server;
129962306a36Sopenharmony_ci	struct svc_process_info process;
130062306a36Sopenharmony_ci	enum svc_auth_status	auth_res;
130162306a36Sopenharmony_ci	unsigned int		aoffset;
130262306a36Sopenharmony_ci	int			rc;
130362306a36Sopenharmony_ci	__be32			*p;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* Will be turned off by GSS integrity and privacy services */
130662306a36Sopenharmony_ci	set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
130762306a36Sopenharmony_ci	/* Will be turned off only when NFSv4 Sessions are used */
130862306a36Sopenharmony_ci	set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
130962306a36Sopenharmony_ci	clear_bit(RQ_DROPME, &rqstp->rq_flags);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	/* Construct the first words of the reply: */
131262306a36Sopenharmony_ci	svcxdr_init_encode(rqstp);
131362306a36Sopenharmony_ci	xdr_stream_encode_be32(xdr, rqstp->rq_xid);
131462306a36Sopenharmony_ci	xdr_stream_encode_be32(xdr, rpc_reply);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 4);
131762306a36Sopenharmony_ci	if (unlikely(!p))
131862306a36Sopenharmony_ci		goto err_short_len;
131962306a36Sopenharmony_ci	if (*p++ != cpu_to_be32(RPC_VERSION))
132062306a36Sopenharmony_ci		goto err_bad_rpc;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	xdr_stream_encode_be32(xdr, rpc_msg_accepted);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	rqstp->rq_prog = be32_to_cpup(p++);
132562306a36Sopenharmony_ci	rqstp->rq_vers = be32_to_cpup(p++);
132662306a36Sopenharmony_ci	rqstp->rq_proc = be32_to_cpup(p);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	for (progp = serv->sv_program; progp; progp = progp->pg_next)
132962306a36Sopenharmony_ci		if (rqstp->rq_prog == progp->pg_prog)
133062306a36Sopenharmony_ci			break;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/*
133362306a36Sopenharmony_ci	 * Decode auth data, and add verifier to reply buffer.
133462306a36Sopenharmony_ci	 * We do this before anything else in order to get a decent
133562306a36Sopenharmony_ci	 * auth verifier.
133662306a36Sopenharmony_ci	 */
133762306a36Sopenharmony_ci	auth_res = svc_authenticate(rqstp);
133862306a36Sopenharmony_ci	/* Also give the program a chance to reject this call: */
133962306a36Sopenharmony_ci	if (auth_res == SVC_OK && progp)
134062306a36Sopenharmony_ci		auth_res = progp->pg_authenticate(rqstp);
134162306a36Sopenharmony_ci	trace_svc_authenticate(rqstp, auth_res);
134262306a36Sopenharmony_ci	switch (auth_res) {
134362306a36Sopenharmony_ci	case SVC_OK:
134462306a36Sopenharmony_ci		break;
134562306a36Sopenharmony_ci	case SVC_GARBAGE:
134662306a36Sopenharmony_ci		goto err_garbage_args;
134762306a36Sopenharmony_ci	case SVC_SYSERR:
134862306a36Sopenharmony_ci		goto err_system_err;
134962306a36Sopenharmony_ci	case SVC_DENIED:
135062306a36Sopenharmony_ci		goto err_bad_auth;
135162306a36Sopenharmony_ci	case SVC_CLOSE:
135262306a36Sopenharmony_ci		goto close;
135362306a36Sopenharmony_ci	case SVC_DROP:
135462306a36Sopenharmony_ci		goto dropit;
135562306a36Sopenharmony_ci	case SVC_COMPLETE:
135662306a36Sopenharmony_ci		goto sendit;
135762306a36Sopenharmony_ci	default:
135862306a36Sopenharmony_ci		pr_warn_once("Unexpected svc_auth_status (%d)\n", auth_res);
135962306a36Sopenharmony_ci		goto err_system_err;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if (progp == NULL)
136362306a36Sopenharmony_ci		goto err_bad_prog;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	switch (progp->pg_init_request(rqstp, progp, &process)) {
136662306a36Sopenharmony_ci	case rpc_success:
136762306a36Sopenharmony_ci		break;
136862306a36Sopenharmony_ci	case rpc_prog_unavail:
136962306a36Sopenharmony_ci		goto err_bad_prog;
137062306a36Sopenharmony_ci	case rpc_prog_mismatch:
137162306a36Sopenharmony_ci		goto err_bad_vers;
137262306a36Sopenharmony_ci	case rpc_proc_unavail:
137362306a36Sopenharmony_ci		goto err_bad_proc;
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	procp = rqstp->rq_procinfo;
137762306a36Sopenharmony_ci	/* Should this check go into the dispatcher? */
137862306a36Sopenharmony_ci	if (!procp || !procp->pc_func)
137962306a36Sopenharmony_ci		goto err_bad_proc;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	/* Syntactic check complete */
138262306a36Sopenharmony_ci	serv->sv_stats->rpccnt++;
138362306a36Sopenharmony_ci	trace_svc_process(rqstp, progp->pg_name);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	aoffset = xdr_stream_pos(xdr);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	/* un-reserve some of the out-queue now that we have a
138862306a36Sopenharmony_ci	 * better idea of reply size
138962306a36Sopenharmony_ci	 */
139062306a36Sopenharmony_ci	if (procp->pc_xdrressize)
139162306a36Sopenharmony_ci		svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* Call the function that processes the request. */
139462306a36Sopenharmony_ci	rc = process.dispatch(rqstp);
139562306a36Sopenharmony_ci	if (procp->pc_release)
139662306a36Sopenharmony_ci		procp->pc_release(rqstp);
139762306a36Sopenharmony_ci	xdr_finish_decode(xdr);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	if (!rc)
140062306a36Sopenharmony_ci		goto dropit;
140162306a36Sopenharmony_ci	if (rqstp->rq_auth_stat != rpc_auth_ok)
140262306a36Sopenharmony_ci		goto err_bad_auth;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if (*rqstp->rq_accept_statp != rpc_success)
140562306a36Sopenharmony_ci		xdr_truncate_encode(xdr, aoffset);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (procp->pc_encode == NULL)
140862306a36Sopenharmony_ci		goto dropit;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci sendit:
141162306a36Sopenharmony_ci	if (svc_authorise(rqstp))
141262306a36Sopenharmony_ci		goto close_xprt;
141362306a36Sopenharmony_ci	return 1;		/* Caller can now send it */
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci dropit:
141662306a36Sopenharmony_ci	svc_authorise(rqstp);	/* doesn't hurt to call this twice */
141762306a36Sopenharmony_ci	dprintk("svc: svc_process dropit\n");
141862306a36Sopenharmony_ci	return 0;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci close:
142162306a36Sopenharmony_ci	svc_authorise(rqstp);
142262306a36Sopenharmony_ciclose_xprt:
142362306a36Sopenharmony_ci	if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
142462306a36Sopenharmony_ci		svc_xprt_close(rqstp->rq_xprt);
142562306a36Sopenharmony_ci	dprintk("svc: svc_process close\n");
142662306a36Sopenharmony_ci	return 0;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cierr_short_len:
142962306a36Sopenharmony_ci	svc_printk(rqstp, "short len %u, dropping request\n",
143062306a36Sopenharmony_ci		   rqstp->rq_arg.len);
143162306a36Sopenharmony_ci	goto close_xprt;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cierr_bad_rpc:
143462306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
143562306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
143662306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_MISMATCH);
143762306a36Sopenharmony_ci	/* Only RPCv2 supported */
143862306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_VERSION);
143962306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_VERSION);
144062306a36Sopenharmony_ci	return 1;	/* don't wrap */
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cierr_bad_auth:
144362306a36Sopenharmony_ci	dprintk("svc: authentication failed (%d)\n",
144462306a36Sopenharmony_ci		be32_to_cpu(rqstp->rq_auth_stat));
144562306a36Sopenharmony_ci	serv->sv_stats->rpcbadauth++;
144662306a36Sopenharmony_ci	/* Restore write pointer to location of reply status: */
144762306a36Sopenharmony_ci	xdr_truncate_encode(xdr, XDR_UNIT * 2);
144862306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_MSG_DENIED);
144962306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, RPC_AUTH_ERROR);
145062306a36Sopenharmony_ci	xdr_stream_encode_be32(xdr, rqstp->rq_auth_stat);
145162306a36Sopenharmony_ci	goto sendit;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cierr_bad_prog:
145462306a36Sopenharmony_ci	dprintk("svc: unknown program %d\n", rqstp->rq_prog);
145562306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
145662306a36Sopenharmony_ci	*rqstp->rq_accept_statp = rpc_prog_unavail;
145762306a36Sopenharmony_ci	goto sendit;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cierr_bad_vers:
146062306a36Sopenharmony_ci	svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
146162306a36Sopenharmony_ci		       rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
146462306a36Sopenharmony_ci	*rqstp->rq_accept_statp = rpc_prog_mismatch;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	/*
146762306a36Sopenharmony_ci	 * svc_authenticate() has already added the verifier and
146862306a36Sopenharmony_ci	 * advanced the stream just past rq_accept_statp.
146962306a36Sopenharmony_ci	 */
147062306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, process.mismatch.lovers);
147162306a36Sopenharmony_ci	xdr_stream_encode_u32(xdr, process.mismatch.hivers);
147262306a36Sopenharmony_ci	goto sendit;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cierr_bad_proc:
147562306a36Sopenharmony_ci	svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
147862306a36Sopenharmony_ci	*rqstp->rq_accept_statp = rpc_proc_unavail;
147962306a36Sopenharmony_ci	goto sendit;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_cierr_garbage_args:
148262306a36Sopenharmony_ci	svc_printk(rqstp, "failed to decode RPC header\n");
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
148562306a36Sopenharmony_ci	*rqstp->rq_accept_statp = rpc_garbage_args;
148662306a36Sopenharmony_ci	goto sendit;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cierr_system_err:
148962306a36Sopenharmony_ci	serv->sv_stats->rpcbadfmt++;
149062306a36Sopenharmony_ci	*rqstp->rq_accept_statp = rpc_system_err;
149162306a36Sopenharmony_ci	goto sendit;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci/**
149562306a36Sopenharmony_ci * svc_process - Execute one RPC transaction
149662306a36Sopenharmony_ci * @rqstp: RPC transaction context
149762306a36Sopenharmony_ci *
149862306a36Sopenharmony_ci */
149962306a36Sopenharmony_civoid svc_process(struct svc_rqst *rqstp)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	struct kvec		*resv = &rqstp->rq_res.head[0];
150262306a36Sopenharmony_ci	__be32 *p;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FAIL_SUNRPC)
150562306a36Sopenharmony_ci	if (!fail_sunrpc.ignore_server_disconnect &&
150662306a36Sopenharmony_ci	    should_fail(&fail_sunrpc.attr, 1))
150762306a36Sopenharmony_ci		svc_xprt_deferred_close(rqstp->rq_xprt);
150862306a36Sopenharmony_ci#endif
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	/*
151162306a36Sopenharmony_ci	 * Setup response xdr_buf.
151262306a36Sopenharmony_ci	 * Initially it has just one page
151362306a36Sopenharmony_ci	 */
151462306a36Sopenharmony_ci	rqstp->rq_next_page = &rqstp->rq_respages[1];
151562306a36Sopenharmony_ci	resv->iov_base = page_address(rqstp->rq_respages[0]);
151662306a36Sopenharmony_ci	resv->iov_len = 0;
151762306a36Sopenharmony_ci	rqstp->rq_res.pages = rqstp->rq_next_page;
151862306a36Sopenharmony_ci	rqstp->rq_res.len = 0;
151962306a36Sopenharmony_ci	rqstp->rq_res.page_base = 0;
152062306a36Sopenharmony_ci	rqstp->rq_res.page_len = 0;
152162306a36Sopenharmony_ci	rqstp->rq_res.buflen = PAGE_SIZE;
152262306a36Sopenharmony_ci	rqstp->rq_res.tail[0].iov_base = NULL;
152362306a36Sopenharmony_ci	rqstp->rq_res.tail[0].iov_len = 0;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	svcxdr_init_decode(rqstp);
152662306a36Sopenharmony_ci	p = xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2);
152762306a36Sopenharmony_ci	if (unlikely(!p))
152862306a36Sopenharmony_ci		goto out_drop;
152962306a36Sopenharmony_ci	rqstp->rq_xid = *p++;
153062306a36Sopenharmony_ci	if (unlikely(*p != rpc_call))
153162306a36Sopenharmony_ci		goto out_baddir;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if (!svc_process_common(rqstp))
153462306a36Sopenharmony_ci		goto out_drop;
153562306a36Sopenharmony_ci	svc_send(rqstp);
153662306a36Sopenharmony_ci	return;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ciout_baddir:
153962306a36Sopenharmony_ci	svc_printk(rqstp, "bad direction 0x%08x, dropping request\n",
154062306a36Sopenharmony_ci		   be32_to_cpu(*p));
154162306a36Sopenharmony_ci	rqstp->rq_server->sv_stats->rpcbadfmt++;
154262306a36Sopenharmony_ciout_drop:
154362306a36Sopenharmony_ci	svc_drop(rqstp);
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
154762306a36Sopenharmony_ci/*
154862306a36Sopenharmony_ci * Process a backchannel RPC request that arrived over an existing
154962306a36Sopenharmony_ci * outbound connection
155062306a36Sopenharmony_ci */
155162306a36Sopenharmony_ciint
155262306a36Sopenharmony_cibc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
155362306a36Sopenharmony_ci	       struct svc_rqst *rqstp)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	struct rpc_task *task;
155662306a36Sopenharmony_ci	int proc_error;
155762306a36Sopenharmony_ci	int error;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	dprintk("svc: %s(%p)\n", __func__, req);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/* Build the svc_rqst used by the common processing routine */
156262306a36Sopenharmony_ci	rqstp->rq_xid = req->rq_xid;
156362306a36Sopenharmony_ci	rqstp->rq_prot = req->rq_xprt->prot;
156462306a36Sopenharmony_ci	rqstp->rq_server = serv;
156562306a36Sopenharmony_ci	rqstp->rq_bc_net = req->rq_xprt->xprt_net;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	rqstp->rq_addrlen = sizeof(req->rq_xprt->addr);
156862306a36Sopenharmony_ci	memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
156962306a36Sopenharmony_ci	memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
157062306a36Sopenharmony_ci	memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	/* Adjust the argument buffer length */
157362306a36Sopenharmony_ci	rqstp->rq_arg.len = req->rq_private_buf.len;
157462306a36Sopenharmony_ci	if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
157562306a36Sopenharmony_ci		rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
157662306a36Sopenharmony_ci		rqstp->rq_arg.page_len = 0;
157762306a36Sopenharmony_ci	} else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len +
157862306a36Sopenharmony_ci			rqstp->rq_arg.page_len)
157962306a36Sopenharmony_ci		rqstp->rq_arg.page_len = rqstp->rq_arg.len -
158062306a36Sopenharmony_ci			rqstp->rq_arg.head[0].iov_len;
158162306a36Sopenharmony_ci	else
158262306a36Sopenharmony_ci		rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len +
158362306a36Sopenharmony_ci			rqstp->rq_arg.page_len;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	/* Reset the response buffer */
158662306a36Sopenharmony_ci	rqstp->rq_res.head[0].iov_len = 0;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/*
158962306a36Sopenharmony_ci	 * Skip the XID and calldir fields because they've already
159062306a36Sopenharmony_ci	 * been processed by the caller.
159162306a36Sopenharmony_ci	 */
159262306a36Sopenharmony_ci	svcxdr_init_decode(rqstp);
159362306a36Sopenharmony_ci	if (!xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2)) {
159462306a36Sopenharmony_ci		error = -EINVAL;
159562306a36Sopenharmony_ci		goto out;
159662306a36Sopenharmony_ci	}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	/* Parse and execute the bc call */
159962306a36Sopenharmony_ci	proc_error = svc_process_common(rqstp);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	atomic_dec(&req->rq_xprt->bc_slot_count);
160262306a36Sopenharmony_ci	if (!proc_error) {
160362306a36Sopenharmony_ci		/* Processing error: drop the request */
160462306a36Sopenharmony_ci		xprt_free_bc_request(req);
160562306a36Sopenharmony_ci		error = -EINVAL;
160662306a36Sopenharmony_ci		goto out;
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci	/* Finally, send the reply synchronously */
160962306a36Sopenharmony_ci	memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf));
161062306a36Sopenharmony_ci	task = rpc_run_bc_task(req);
161162306a36Sopenharmony_ci	if (IS_ERR(task)) {
161262306a36Sopenharmony_ci		error = PTR_ERR(task);
161362306a36Sopenharmony_ci		goto out;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	WARN_ON_ONCE(atomic_read(&task->tk_count) != 1);
161762306a36Sopenharmony_ci	error = task->tk_status;
161862306a36Sopenharmony_ci	rpc_put_task(task);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ciout:
162162306a36Sopenharmony_ci	dprintk("svc: %s(), error=%d\n", __func__, error);
162262306a36Sopenharmony_ci	return error;
162362306a36Sopenharmony_ci}
162462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bc_svc_process);
162562306a36Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci/**
162862306a36Sopenharmony_ci * svc_max_payload - Return transport-specific limit on the RPC payload
162962306a36Sopenharmony_ci * @rqstp: RPC transaction context
163062306a36Sopenharmony_ci *
163162306a36Sopenharmony_ci * Returns the maximum number of payload bytes the current transport
163262306a36Sopenharmony_ci * allows.
163362306a36Sopenharmony_ci */
163462306a36Sopenharmony_ciu32 svc_max_payload(const struct svc_rqst *rqstp)
163562306a36Sopenharmony_ci{
163662306a36Sopenharmony_ci	u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	if (rqstp->rq_server->sv_max_payload < max)
163962306a36Sopenharmony_ci		max = rqstp->rq_server->sv_max_payload;
164062306a36Sopenharmony_ci	return max;
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_max_payload);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci/**
164562306a36Sopenharmony_ci * svc_proc_name - Return RPC procedure name in string form
164662306a36Sopenharmony_ci * @rqstp: svc_rqst to operate on
164762306a36Sopenharmony_ci *
164862306a36Sopenharmony_ci * Return value:
164962306a36Sopenharmony_ci *   Pointer to a NUL-terminated string
165062306a36Sopenharmony_ci */
165162306a36Sopenharmony_ciconst char *svc_proc_name(const struct svc_rqst *rqstp)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	if (rqstp && rqstp->rq_procinfo)
165462306a36Sopenharmony_ci		return rqstp->rq_procinfo->pc_name;
165562306a36Sopenharmony_ci	return "unknown";
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci/**
166062306a36Sopenharmony_ci * svc_encode_result_payload - mark a range of bytes as a result payload
166162306a36Sopenharmony_ci * @rqstp: svc_rqst to operate on
166262306a36Sopenharmony_ci * @offset: payload's byte offset in rqstp->rq_res
166362306a36Sopenharmony_ci * @length: size of payload, in bytes
166462306a36Sopenharmony_ci *
166562306a36Sopenharmony_ci * Returns zero on success, or a negative errno if a permanent
166662306a36Sopenharmony_ci * error occurred.
166762306a36Sopenharmony_ci */
166862306a36Sopenharmony_ciint svc_encode_result_payload(struct svc_rqst *rqstp, unsigned int offset,
166962306a36Sopenharmony_ci			      unsigned int length)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	return rqstp->rq_xprt->xpt_ops->xpo_result_payload(rqstp, offset,
167262306a36Sopenharmony_ci							   length);
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_encode_result_payload);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci/**
167762306a36Sopenharmony_ci * svc_fill_write_vector - Construct data argument for VFS write call
167862306a36Sopenharmony_ci * @rqstp: svc_rqst to operate on
167962306a36Sopenharmony_ci * @payload: xdr_buf containing only the write data payload
168062306a36Sopenharmony_ci *
168162306a36Sopenharmony_ci * Fills in rqstp::rq_vec, and returns the number of elements.
168262306a36Sopenharmony_ci */
168362306a36Sopenharmony_ciunsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
168462306a36Sopenharmony_ci				   struct xdr_buf *payload)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	struct page **pages = payload->pages;
168762306a36Sopenharmony_ci	struct kvec *first = payload->head;
168862306a36Sopenharmony_ci	struct kvec *vec = rqstp->rq_vec;
168962306a36Sopenharmony_ci	size_t total = payload->len;
169062306a36Sopenharmony_ci	unsigned int i;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/* Some types of transport can present the write payload
169362306a36Sopenharmony_ci	 * entirely in rq_arg.pages. In this case, @first is empty.
169462306a36Sopenharmony_ci	 */
169562306a36Sopenharmony_ci	i = 0;
169662306a36Sopenharmony_ci	if (first->iov_len) {
169762306a36Sopenharmony_ci		vec[i].iov_base = first->iov_base;
169862306a36Sopenharmony_ci		vec[i].iov_len = min_t(size_t, total, first->iov_len);
169962306a36Sopenharmony_ci		total -= vec[i].iov_len;
170062306a36Sopenharmony_ci		++i;
170162306a36Sopenharmony_ci	}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	while (total) {
170462306a36Sopenharmony_ci		vec[i].iov_base = page_address(*pages);
170562306a36Sopenharmony_ci		vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
170662306a36Sopenharmony_ci		total -= vec[i].iov_len;
170762306a36Sopenharmony_ci		++i;
170862306a36Sopenharmony_ci		++pages;
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	WARN_ON_ONCE(i > ARRAY_SIZE(rqstp->rq_vec));
171262306a36Sopenharmony_ci	return i;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_fill_write_vector);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/**
171762306a36Sopenharmony_ci * svc_fill_symlink_pathname - Construct pathname argument for VFS symlink call
171862306a36Sopenharmony_ci * @rqstp: svc_rqst to operate on
171962306a36Sopenharmony_ci * @first: buffer containing first section of pathname
172062306a36Sopenharmony_ci * @p: buffer containing remaining section of pathname
172162306a36Sopenharmony_ci * @total: total length of the pathname argument
172262306a36Sopenharmony_ci *
172362306a36Sopenharmony_ci * The VFS symlink API demands a NUL-terminated pathname in mapped memory.
172462306a36Sopenharmony_ci * Returns pointer to a NUL-terminated string, or an ERR_PTR. Caller must free
172562306a36Sopenharmony_ci * the returned string.
172662306a36Sopenharmony_ci */
172762306a36Sopenharmony_cichar *svc_fill_symlink_pathname(struct svc_rqst *rqstp, struct kvec *first,
172862306a36Sopenharmony_ci				void *p, size_t total)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	size_t len, remaining;
173162306a36Sopenharmony_ci	char *result, *dst;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	result = kmalloc(total + 1, GFP_KERNEL);
173462306a36Sopenharmony_ci	if (!result)
173562306a36Sopenharmony_ci		return ERR_PTR(-ESERVERFAULT);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	dst = result;
173862306a36Sopenharmony_ci	remaining = total;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	len = min_t(size_t, total, first->iov_len);
174162306a36Sopenharmony_ci	if (len) {
174262306a36Sopenharmony_ci		memcpy(dst, first->iov_base, len);
174362306a36Sopenharmony_ci		dst += len;
174462306a36Sopenharmony_ci		remaining -= len;
174562306a36Sopenharmony_ci	}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (remaining) {
174862306a36Sopenharmony_ci		len = min_t(size_t, remaining, PAGE_SIZE);
174962306a36Sopenharmony_ci		memcpy(dst, p, len);
175062306a36Sopenharmony_ci		dst += len;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	*dst = '\0';
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	/* Sanity check: Linux doesn't allow the pathname argument to
175662306a36Sopenharmony_ci	 * contain a NUL byte.
175762306a36Sopenharmony_ci	 */
175862306a36Sopenharmony_ci	if (strlen(result) != total) {
175962306a36Sopenharmony_ci		kfree(result);
176062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci	return result;
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_fill_symlink_pathname);
1765