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 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 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: 112746c6237SXiongfeng Wang return strlcpy(buf, "auto\n", 20); 11342a7fc4aSGreg Banks case SVC_POOL_GLOBAL: 114746c6237SXiongfeng Wang return strlcpy(buf, "global\n", 20); 11542a7fc4aSGreg Banks case SVC_POOL_PERCPU: 116746c6237SXiongfeng Wang return strlcpy(buf, "percpu\n", 20); 11742a7fc4aSGreg Banks case SVC_POOL_PERNODE: 118746c6237SXiongfeng Wang return strlcpy(buf, "pernode\n", 20); 11942a7fc4aSGreg Banks default: 120746c6237SXiongfeng Wang return sprintf(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 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 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 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 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 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 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 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 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 359bfd24160SGreg Banks /* 360bfd24160SGreg Banks * Use the mapping mode to choose a pool for a given CPU. 361bfd24160SGreg Banks * Used when enqueueing an incoming RPC. Always returns 362bfd24160SGreg Banks * a non-NULL pool pointer. 363bfd24160SGreg Banks */ 364bfd24160SGreg Banks struct svc_pool * 365bfd24160SGreg Banks svc_pool_for_cpu(struct svc_serv *serv, int cpu) 366bfd24160SGreg Banks { 367bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 368bfd24160SGreg Banks unsigned int pidx = 0; 369bfd24160SGreg Banks 37093aa619eSNeilBrown if (serv->sv_nrpools <= 1) 37193aa619eSNeilBrown return serv->sv_pools; 37293aa619eSNeilBrown 373bfd24160SGreg Banks switch (m->mode) { 374bfd24160SGreg Banks case SVC_POOL_PERCPU: 375bfd24160SGreg Banks pidx = m->to_pool[cpu]; 376bfd24160SGreg Banks break; 377bfd24160SGreg Banks case SVC_POOL_PERNODE: 378bfd24160SGreg Banks pidx = m->to_pool[cpu_to_node(cpu)]; 379bfd24160SGreg Banks break; 380bfd24160SGreg Banks } 38193aa619eSNeilBrown 382bfd24160SGreg Banks return &serv->sv_pools[pidx % serv->sv_nrpools]; 383bfd24160SGreg Banks } 384bfd24160SGreg Banks 385bb2224dfSStanislav Kinsbursky int svc_rpcb_setup(struct svc_serv *serv, struct net *net) 386d9908560SStanislav Kinsbursky { 387d9908560SStanislav Kinsbursky int err; 388d9908560SStanislav Kinsbursky 389bee42f68SStanislav Kinsbursky err = rpcb_create_local(net); 390d9908560SStanislav Kinsbursky if (err) 391d9908560SStanislav Kinsbursky return err; 392d9908560SStanislav Kinsbursky 393d9908560SStanislav Kinsbursky /* Remove any stale portmap registrations */ 394bee42f68SStanislav Kinsbursky svc_unregister(serv, net); 395d9908560SStanislav Kinsbursky return 0; 396d9908560SStanislav Kinsbursky } 397bb2224dfSStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_setup); 398d9908560SStanislav Kinsbursky 3995ecebb7cSStanislav Kinsbursky void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) 400d9908560SStanislav Kinsbursky { 4015ecebb7cSStanislav Kinsbursky svc_unregister(serv, net); 4025ecebb7cSStanislav Kinsbursky rpcb_put_local(net); 403d9908560SStanislav Kinsbursky } 40416d05870SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); 405d9908560SStanislav Kinsbursky 406d9908560SStanislav Kinsbursky static int svc_uses_rpcbind(struct svc_serv *serv) 407d9908560SStanislav Kinsbursky { 408d9908560SStanislav Kinsbursky struct svc_program *progp; 409d9908560SStanislav Kinsbursky unsigned int i; 410d9908560SStanislav Kinsbursky 411d9908560SStanislav Kinsbursky for (progp = serv->sv_program; progp; progp = progp->pg_next) { 412d9908560SStanislav Kinsbursky for (i = 0; i < progp->pg_nvers; i++) { 413d9908560SStanislav Kinsbursky if (progp->pg_vers[i] == NULL) 414d9908560SStanislav Kinsbursky continue; 41505a45a2dSJeff Layton if (!progp->pg_vers[i]->vs_hidden) 416d9908560SStanislav Kinsbursky return 1; 417d9908560SStanislav Kinsbursky } 418d9908560SStanislav Kinsbursky } 419d9908560SStanislav Kinsbursky 420d9908560SStanislav Kinsbursky return 0; 421d9908560SStanislav Kinsbursky } 422bfd24160SGreg Banks 4239793f7c8SStanislav Kinsbursky int svc_bind(struct svc_serv *serv, struct net *net) 4249793f7c8SStanislav Kinsbursky { 4259793f7c8SStanislav Kinsbursky if (!svc_uses_rpcbind(serv)) 4269793f7c8SStanislav Kinsbursky return 0; 4279793f7c8SStanislav Kinsbursky return svc_rpcb_setup(serv, net); 4289793f7c8SStanislav Kinsbursky } 4299793f7c8SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_bind); 4309793f7c8SStanislav Kinsbursky 431d0025268STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL) 432d0025268STrond Myklebust static void 433d0025268STrond Myklebust __svc_init_bc(struct svc_serv *serv) 434d0025268STrond Myklebust { 435d0025268STrond Myklebust INIT_LIST_HEAD(&serv->sv_cb_list); 436d0025268STrond Myklebust spin_lock_init(&serv->sv_cb_lock); 437d0025268STrond Myklebust init_waitqueue_head(&serv->sv_cb_waitq); 438d0025268STrond Myklebust } 439d0025268STrond Myklebust #else 440d0025268STrond Myklebust static void 441d0025268STrond Myklebust __svc_init_bc(struct svc_serv *serv) 442d0025268STrond Myklebust { 443d0025268STrond Myklebust } 444d0025268STrond Myklebust #endif 445d0025268STrond Myklebust 446bfd24160SGreg Banks /* 4471da177e4SLinus Torvalds * Create an RPC service 4481da177e4SLinus Torvalds */ 449a7455442SGreg Banks static struct svc_serv * 450a7455442SGreg Banks __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, 451*37902c63SChuck Lever int (*threadfn)(void *data)) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds struct svc_serv *serv; 454ea339d46SChuck Lever unsigned int vers; 4551da177e4SLinus Torvalds unsigned int xdrsize; 4563262c816SGreg Banks unsigned int i; 4571da177e4SLinus Torvalds 4580da974f4SPanagiotis Issaris if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) 4591da177e4SLinus Torvalds return NULL; 4609ba02638SAndreas Gruenbacher serv->sv_name = prog->pg_name; 4611da177e4SLinus Torvalds serv->sv_program = prog; 462ec52361dSNeilBrown kref_init(&serv->sv_refcnt); 4631da177e4SLinus Torvalds serv->sv_stats = prog->pg_stats; 464c6b0a9f8SNeilBrown if (bufsize > RPCSVC_MAXPAYLOAD) 465c6b0a9f8SNeilBrown bufsize = RPCSVC_MAXPAYLOAD; 466c6b0a9f8SNeilBrown serv->sv_max_payload = bufsize? bufsize : 4096; 467c6b0a9f8SNeilBrown serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); 468*37902c63SChuck Lever serv->sv_threadfn = threadfn; 4691da177e4SLinus Torvalds xdrsize = 0; 4709ba02638SAndreas Gruenbacher while (prog) { 4719ba02638SAndreas Gruenbacher prog->pg_lovers = prog->pg_nvers-1; 4721da177e4SLinus Torvalds for (vers=0; vers<prog->pg_nvers ; vers++) 4731da177e4SLinus Torvalds if (prog->pg_vers[vers]) { 4741da177e4SLinus Torvalds prog->pg_hivers = vers; 4751da177e4SLinus Torvalds if (prog->pg_lovers > vers) 4761da177e4SLinus Torvalds prog->pg_lovers = vers; 4771da177e4SLinus Torvalds if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) 4781da177e4SLinus Torvalds xdrsize = prog->pg_vers[vers]->vs_xdrsize; 4791da177e4SLinus Torvalds } 4809ba02638SAndreas Gruenbacher prog = prog->pg_next; 4819ba02638SAndreas Gruenbacher } 4821da177e4SLinus Torvalds serv->sv_xdrsize = xdrsize; 4831da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_tempsocks); 4841da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_permsocks); 485ff861c4dSKees Cook timer_setup(&serv->sv_temptimer, NULL, 0); 4861da177e4SLinus Torvalds spin_lock_init(&serv->sv_lock); 4871da177e4SLinus Torvalds 488d0025268STrond Myklebust __svc_init_bc(serv); 489d0025268STrond Myklebust 490a7455442SGreg Banks serv->sv_nrpools = npools; 4913262c816SGreg Banks serv->sv_pools = 492cd861280SRobert P. J. Day kcalloc(serv->sv_nrpools, sizeof(struct svc_pool), 4933262c816SGreg Banks GFP_KERNEL); 4943262c816SGreg Banks if (!serv->sv_pools) { 4953262c816SGreg Banks kfree(serv); 4963262c816SGreg Banks return NULL; 4973262c816SGreg Banks } 4983262c816SGreg Banks 4993262c816SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 5003262c816SGreg Banks struct svc_pool *pool = &serv->sv_pools[i]; 5013262c816SGreg Banks 50246121cf7SChuck Lever dprintk("svc: initialising pool %u for %s\n", 5033262c816SGreg Banks i, serv->sv_name); 5043262c816SGreg Banks 5053262c816SGreg Banks pool->sp_id = i; 5063262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_sockets); 507a7455442SGreg Banks INIT_LIST_HEAD(&pool->sp_all_threads); 5083262c816SGreg Banks spin_lock_init(&pool->sp_lock); 5093262c816SGreg Banks } 5103262c816SGreg Banks 5111da177e4SLinus Torvalds return serv; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514*37902c63SChuck Lever /** 515*37902c63SChuck Lever * svc_create - Create an RPC service 516*37902c63SChuck Lever * @prog: the RPC program the new service will handle 517*37902c63SChuck Lever * @bufsize: maximum message size for @prog 518*37902c63SChuck Lever * @threadfn: a function to service RPC requests for @prog 519*37902c63SChuck Lever * 520*37902c63SChuck Lever * Returns an instantiated struct svc_serv object or NULL. 521*37902c63SChuck Lever */ 522*37902c63SChuck Lever struct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize, 523*37902c63SChuck Lever int (*threadfn)(void *data)) 524a7455442SGreg Banks { 525*37902c63SChuck Lever return __svc_create(prog, bufsize, 1, threadfn); 526a7455442SGreg Banks } 52724c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create); 528a7455442SGreg Banks 529*37902c63SChuck Lever /** 530*37902c63SChuck Lever * svc_create_pooled - Create an RPC service with pooled threads 531*37902c63SChuck Lever * @prog: the RPC program the new service will handle 532*37902c63SChuck Lever * @bufsize: maximum message size for @prog 533*37902c63SChuck Lever * @threadfn: a function to service RPC requests for @prog 534*37902c63SChuck Lever * 535*37902c63SChuck Lever * Returns an instantiated struct svc_serv object or NULL. 536*37902c63SChuck Lever */ 537*37902c63SChuck Lever struct svc_serv *svc_create_pooled(struct svc_program *prog, 538*37902c63SChuck Lever unsigned int bufsize, 539*37902c63SChuck Lever int (*threadfn)(void *data)) 540a7455442SGreg Banks { 541a7455442SGreg Banks struct svc_serv *serv; 54242a7fc4aSGreg Banks unsigned int npools = svc_pool_map_get(); 543a7455442SGreg Banks 544*37902c63SChuck Lever serv = __svc_create(prog, bufsize, npools, threadfn); 545067f96efSJeff Layton if (!serv) 546067f96efSJeff Layton goto out_err; 547a7455442SGreg Banks return serv; 548067f96efSJeff Layton out_err: 54993aa619eSNeilBrown svc_pool_map_put(npools); 550067f96efSJeff Layton return NULL; 551a7455442SGreg Banks } 55224c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create_pooled); 553a7455442SGreg Banks 5541da177e4SLinus Torvalds /* 555bedbdd8bSNeil Brown * Destroy an RPC service. Should be called with appropriate locking to 5562a36395fSNeilBrown * protect sv_permsocks and sv_tempsocks. 5571da177e4SLinus Torvalds */ 5581da177e4SLinus Torvalds void 559ec52361dSNeilBrown svc_destroy(struct kref *ref) 5601da177e4SLinus Torvalds { 561ec52361dSNeilBrown struct svc_serv *serv = container_of(ref, struct svc_serv, sv_refcnt); 5621da177e4SLinus Torvalds 563ec52361dSNeilBrown dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name); 56436bdfc8bSGreg Banks del_timer_sync(&serv->sv_temptimer); 565074d0f67SStanislav Kinsbursky 5667b147f1fSStanislav Kinsbursky /* 5677b147f1fSStanislav Kinsbursky * The last user is gone and thus all sockets have to be destroyed to 5687b147f1fSStanislav Kinsbursky * the point. Check this. 5697b147f1fSStanislav Kinsbursky */ 5707b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_permsocks)); 5717b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_tempsocks)); 572cda1fd4aSNeilBrown 5731da177e4SLinus Torvalds cache_clean_deferred(serv); 5741da177e4SLinus Torvalds 57593aa619eSNeilBrown svc_pool_map_put(serv->sv_nrpools); 57642a7fc4aSGreg Banks 5773262c816SGreg Banks kfree(serv->sv_pools); 5781da177e4SLinus Torvalds kfree(serv); 5791da177e4SLinus Torvalds } 58024c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_destroy); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds /* 5831da177e4SLinus Torvalds * Allocate an RPC server's buffer space. 5844ff923ceSChuck Lever * We allocate pages and place them in rq_pages. 5851da177e4SLinus Torvalds */ 5861da177e4SLinus Torvalds static int 58711fd165cSEric Dumazet svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node) 5881da177e4SLinus Torvalds { 5890dc220f0SChuck Lever unsigned int pages, arghi; 5901da177e4SLinus Torvalds 591ba17686fSAndy Adamson /* bc_xprt uses fore channel allocated buffers */ 592ba17686fSAndy Adamson if (svc_is_backchannel(rqstp)) 593ba17686fSAndy Adamson return 1; 594ba17686fSAndy Adamson 595c6b0a9f8SNeilBrown pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. 596c6b0a9f8SNeilBrown * We assume one is at most one page 597c6b0a9f8SNeilBrown */ 5981da177e4SLinus Torvalds arghi = 0; 599b25cd058SWeston Andros Adamson WARN_ON_ONCE(pages > RPCSVC_MAXPAGES); 600b25cd058SWeston Andros Adamson if (pages > RPCSVC_MAXPAGES) 601b25cd058SWeston Andros Adamson pages = RPCSVC_MAXPAGES; 6021da177e4SLinus Torvalds while (pages) { 60311fd165cSEric Dumazet struct page *p = alloc_pages_node(node, GFP_KERNEL, 0); 6041da177e4SLinus Torvalds if (!p) 6051da177e4SLinus Torvalds break; 60644524359SNeilBrown rqstp->rq_pages[arghi++] = p; 6071da177e4SLinus Torvalds pages--; 6081da177e4SLinus Torvalds } 6090dc220f0SChuck Lever return pages == 0; 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds /* 6131da177e4SLinus Torvalds * Release an RPC server buffer 6141da177e4SLinus Torvalds */ 6151da177e4SLinus Torvalds static void 6161da177e4SLinus Torvalds svc_release_buffer(struct svc_rqst *rqstp) 6171da177e4SLinus Torvalds { 61850c8bb13SChuck Lever unsigned int i; 61950c8bb13SChuck Lever 62044524359SNeilBrown for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) 62144524359SNeilBrown if (rqstp->rq_pages[i]) 62244524359SNeilBrown put_page(rqstp->rq_pages[i]); 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6250113ab34SJeff Layton struct svc_rqst * 6261b6dc1dfSJeff Layton svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) 6270113ab34SJeff Layton { 6280113ab34SJeff Layton struct svc_rqst *rqstp; 6290113ab34SJeff Layton 63011fd165cSEric Dumazet rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node); 6310113ab34SJeff Layton if (!rqstp) 6321b6dc1dfSJeff Layton return rqstp; 6330113ab34SJeff Layton 634b1691bc0SJeff Layton __set_bit(RQ_BUSY, &rqstp->rq_flags); 635b1691bc0SJeff Layton spin_lock_init(&rqstp->rq_lock); 636b1691bc0SJeff Layton rqstp->rq_server = serv; 637b1691bc0SJeff Layton rqstp->rq_pool = pool; 6381b6dc1dfSJeff Layton 6395191955dSChuck Lever rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0); 6405191955dSChuck Lever if (!rqstp->rq_scratch_page) 6415191955dSChuck Lever goto out_enomem; 6425191955dSChuck Lever 6431b6dc1dfSJeff Layton rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6441b6dc1dfSJeff Layton if (!rqstp->rq_argp) 6451b6dc1dfSJeff Layton goto out_enomem; 6461b6dc1dfSJeff Layton 6471b6dc1dfSJeff Layton rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6481b6dc1dfSJeff Layton if (!rqstp->rq_resp) 6491b6dc1dfSJeff Layton goto out_enomem; 6501b6dc1dfSJeff Layton 6511b6dc1dfSJeff Layton if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node)) 6521b6dc1dfSJeff Layton goto out_enomem; 6531b6dc1dfSJeff Layton 6541b6dc1dfSJeff Layton return rqstp; 6551b6dc1dfSJeff Layton out_enomem: 6561b6dc1dfSJeff Layton svc_rqst_free(rqstp); 6571b6dc1dfSJeff Layton return NULL; 6581b6dc1dfSJeff Layton } 6591b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_alloc); 6601b6dc1dfSJeff Layton 6616b044fbaSNeilBrown static struct svc_rqst * 6621b6dc1dfSJeff Layton svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) 6631b6dc1dfSJeff Layton { 6641b6dc1dfSJeff Layton struct svc_rqst *rqstp; 6651b6dc1dfSJeff Layton 6661b6dc1dfSJeff Layton rqstp = svc_rqst_alloc(serv, pool, node); 6671b6dc1dfSJeff Layton if (!rqstp) 6681b6dc1dfSJeff Layton return ERR_PTR(-ENOMEM); 6691b6dc1dfSJeff Layton 670ec52361dSNeilBrown svc_get(serv); 6712a36395fSNeilBrown spin_lock_bh(&serv->sv_lock); 6722a36395fSNeilBrown serv->sv_nrthreads += 1; 6732a36395fSNeilBrown spin_unlock_bh(&serv->sv_lock); 6742a36395fSNeilBrown 6750113ab34SJeff Layton spin_lock_bh(&pool->sp_lock); 6760113ab34SJeff Layton pool->sp_nrthreads++; 67781244386SJeff Layton list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); 6780113ab34SJeff Layton spin_unlock_bh(&pool->sp_lock); 6790113ab34SJeff Layton return rqstp; 6800113ab34SJeff Layton } 6810113ab34SJeff Layton 6821da177e4SLinus Torvalds /* 683a7455442SGreg Banks * Choose a pool in which to create a new thread, for svc_set_num_threads 684a7455442SGreg Banks */ 685a7455442SGreg Banks static inline struct svc_pool * 686a7455442SGreg Banks choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 687a7455442SGreg Banks { 688a7455442SGreg Banks if (pool != NULL) 689a7455442SGreg Banks return pool; 690a7455442SGreg Banks 691a7455442SGreg Banks return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; 692a7455442SGreg Banks } 693a7455442SGreg Banks 694a7455442SGreg Banks /* 695a7455442SGreg Banks * Choose a thread to kill, for svc_set_num_threads 696a7455442SGreg Banks */ 697a7455442SGreg Banks static inline struct task_struct * 698a7455442SGreg Banks choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 699a7455442SGreg Banks { 700a7455442SGreg Banks unsigned int i; 701a7455442SGreg Banks struct task_struct *task = NULL; 702a7455442SGreg Banks 703a7455442SGreg Banks if (pool != NULL) { 704a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 705a7455442SGreg Banks } else { 706a7455442SGreg Banks /* choose a pool in round-robin fashion */ 707a7455442SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 708a7455442SGreg Banks pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; 709a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 710a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) 711a7455442SGreg Banks goto found_pool; 712a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 713a7455442SGreg Banks } 714a7455442SGreg Banks return NULL; 715a7455442SGreg Banks } 716a7455442SGreg Banks 717a7455442SGreg Banks found_pool: 718a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) { 719a7455442SGreg Banks struct svc_rqst *rqstp; 720a7455442SGreg Banks 721a7455442SGreg Banks /* 722a7455442SGreg Banks * Remove from the pool->sp_all_threads list 723a7455442SGreg Banks * so we don't try to kill it again. 724a7455442SGreg Banks */ 725a7455442SGreg Banks rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); 72681244386SJeff Layton set_bit(RQ_VICTIM, &rqstp->rq_flags); 72781244386SJeff Layton list_del_rcu(&rqstp->rq_all); 728a7455442SGreg Banks task = rqstp->rq_task; 729a7455442SGreg Banks } 730a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 731a7455442SGreg Banks 732a7455442SGreg Banks return task; 733a7455442SGreg Banks } 734a7455442SGreg Banks 7359e0d8768STrond Myklebust /* create new threads */ 7369e0d8768STrond Myklebust static int 7379e0d8768STrond Myklebust svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 7389e0d8768STrond Myklebust { 7399e0d8768STrond Myklebust struct svc_rqst *rqstp; 7409e0d8768STrond Myklebust struct task_struct *task; 7419e0d8768STrond Myklebust struct svc_pool *chosen_pool; 7429e0d8768STrond Myklebust unsigned int state = serv->sv_nrthreads-1; 7439e0d8768STrond Myklebust int node; 7449e0d8768STrond Myklebust 7459e0d8768STrond Myklebust do { 7469e0d8768STrond Myklebust nrservs--; 7479e0d8768STrond Myklebust chosen_pool = choose_pool(serv, pool, &state); 7489e0d8768STrond Myklebust 7499e0d8768STrond Myklebust node = svc_pool_map_get_node(chosen_pool->sp_id); 7509e0d8768STrond Myklebust rqstp = svc_prepare_thread(serv, chosen_pool, node); 7519e0d8768STrond Myklebust if (IS_ERR(rqstp)) 7529e0d8768STrond Myklebust return PTR_ERR(rqstp); 7539e0d8768STrond Myklebust 754*37902c63SChuck Lever task = kthread_create_on_node(serv->sv_threadfn, rqstp, 7559e0d8768STrond Myklebust node, "%s", serv->sv_name); 7569e0d8768STrond Myklebust if (IS_ERR(task)) { 7579e0d8768STrond Myklebust svc_exit_thread(rqstp); 7589e0d8768STrond Myklebust return PTR_ERR(task); 7599e0d8768STrond Myklebust } 7609e0d8768STrond Myklebust 7619e0d8768STrond Myklebust rqstp->rq_task = task; 7629e0d8768STrond Myklebust if (serv->sv_nrpools > 1) 7639e0d8768STrond Myklebust svc_pool_map_set_cpumask(task, chosen_pool->sp_id); 7649e0d8768STrond Myklebust 7659e0d8768STrond Myklebust svc_sock_update_bufs(serv); 7669e0d8768STrond Myklebust wake_up_process(task); 7679e0d8768STrond Myklebust } while (nrservs > 0); 7689e0d8768STrond Myklebust 7699e0d8768STrond Myklebust return 0; 7709e0d8768STrond Myklebust } 7719e0d8768STrond Myklebust 772a7455442SGreg Banks /* 773a7455442SGreg Banks * Create or destroy enough new threads to make the number 774a7455442SGreg Banks * of threads the given number. If `pool' is non-NULL, applies 775a7455442SGreg Banks * only to threads in that pool, otherwise round-robins between 77694cf3179SJ. Bruce Fields * all pools. Caller must ensure that mutual exclusion between this and 77794cf3179SJ. Bruce Fields * server startup or shutdown. 778a7455442SGreg Banks */ 779a7455442SGreg Banks 780ed6473ddSTrond Myklebust /* destroy old threads */ 781ed6473ddSTrond Myklebust static int 782ed6473ddSTrond Myklebust svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 783ed6473ddSTrond Myklebust { 784ed6473ddSTrond Myklebust struct task_struct *task; 785ed6473ddSTrond Myklebust unsigned int state = serv->sv_nrthreads-1; 786ed6473ddSTrond Myklebust 787ed6473ddSTrond Myklebust /* destroy old threads */ 788ed6473ddSTrond Myklebust do { 789ed6473ddSTrond Myklebust task = choose_victim(serv, pool, &state); 790ed6473ddSTrond Myklebust if (task == NULL) 791ed6473ddSTrond Myklebust break; 792ed6473ddSTrond Myklebust kthread_stop(task); 793ed6473ddSTrond Myklebust nrservs++; 794ed6473ddSTrond Myklebust } while (nrservs < 0); 795ed6473ddSTrond Myklebust return 0; 796ed6473ddSTrond Myklebust } 797ed6473ddSTrond Myklebust 798ed6473ddSTrond Myklebust int 7993ebdbe52SNeilBrown svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 800ed6473ddSTrond Myklebust { 801ed6473ddSTrond Myklebust if (pool == NULL) { 802ec52361dSNeilBrown nrservs -= serv->sv_nrthreads; 803ed6473ddSTrond Myklebust } else { 804ed6473ddSTrond Myklebust spin_lock_bh(&pool->sp_lock); 805ed6473ddSTrond Myklebust nrservs -= pool->sp_nrthreads; 806ed6473ddSTrond Myklebust spin_unlock_bh(&pool->sp_lock); 807ed6473ddSTrond Myklebust } 808ed6473ddSTrond Myklebust 809ed6473ddSTrond Myklebust if (nrservs > 0) 810ed6473ddSTrond Myklebust return svc_start_kthreads(serv, pool, nrservs); 811ed6473ddSTrond Myklebust if (nrservs < 0) 812ed6473ddSTrond Myklebust return svc_stop_kthreads(serv, pool, nrservs); 813ed6473ddSTrond Myklebust return 0; 814ed6473ddSTrond Myklebust } 8153ebdbe52SNeilBrown EXPORT_SYMBOL_GPL(svc_set_num_threads); 816ed6473ddSTrond Myklebust 8172f0f88f4SChuck Lever /** 8182f0f88f4SChuck Lever * svc_rqst_replace_page - Replace one page in rq_pages[] 8192f0f88f4SChuck Lever * @rqstp: svc_rqst with pages to replace 8202f0f88f4SChuck Lever * @page: replacement page 8212f0f88f4SChuck Lever * 8222f0f88f4SChuck Lever * When replacing a page in rq_pages, batch the release of the 8232f0f88f4SChuck Lever * replaced pages to avoid hammering the page allocator. 8242f0f88f4SChuck Lever */ 8252f0f88f4SChuck Lever void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page) 8262f0f88f4SChuck Lever { 8272f0f88f4SChuck Lever if (*rqstp->rq_next_page) { 8282f0f88f4SChuck Lever if (!pagevec_space(&rqstp->rq_pvec)) 8292f0f88f4SChuck Lever __pagevec_release(&rqstp->rq_pvec); 8302f0f88f4SChuck Lever pagevec_add(&rqstp->rq_pvec, *rqstp->rq_next_page); 8312f0f88f4SChuck Lever } 8322f0f88f4SChuck Lever 8332f0f88f4SChuck Lever get_page(page); 8342f0f88f4SChuck Lever *(rqstp->rq_next_page++) = page; 8352f0f88f4SChuck Lever } 8362f0f88f4SChuck Lever EXPORT_SYMBOL_GPL(svc_rqst_replace_page); 8372f0f88f4SChuck Lever 838a7455442SGreg Banks /* 8393c519914SJeff Layton * Called from a server thread as it's exiting. Caller must hold the "service 8403c519914SJeff Layton * mutex" for the service. 8411da177e4SLinus Torvalds */ 8421da177e4SLinus Torvalds void 8431b6dc1dfSJeff Layton svc_rqst_free(struct svc_rqst *rqstp) 8441da177e4SLinus Torvalds { 8451da177e4SLinus Torvalds svc_release_buffer(rqstp); 846b9f83ffaSYunjian Wang if (rqstp->rq_scratch_page) 8475191955dSChuck Lever put_page(rqstp->rq_scratch_page); 8481da177e4SLinus Torvalds kfree(rqstp->rq_resp); 8491da177e4SLinus Torvalds kfree(rqstp->rq_argp); 8501da177e4SLinus Torvalds kfree(rqstp->rq_auth_data); 8511b6dc1dfSJeff Layton kfree_rcu(rqstp, rq_rcu_head); 8521b6dc1dfSJeff Layton } 8531b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_free); 8541b6dc1dfSJeff Layton 8551b6dc1dfSJeff Layton void 8561b6dc1dfSJeff Layton svc_exit_thread(struct svc_rqst *rqstp) 8571b6dc1dfSJeff Layton { 8581b6dc1dfSJeff Layton struct svc_serv *serv = rqstp->rq_server; 8591b6dc1dfSJeff Layton struct svc_pool *pool = rqstp->rq_pool; 8603262c816SGreg Banks 8613262c816SGreg Banks spin_lock_bh(&pool->sp_lock); 8623262c816SGreg Banks pool->sp_nrthreads--; 86381244386SJeff Layton if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags)) 86481244386SJeff Layton list_del_rcu(&rqstp->rq_all); 8653262c816SGreg Banks spin_unlock_bh(&pool->sp_lock); 8663262c816SGreg Banks 8672a36395fSNeilBrown spin_lock_bh(&serv->sv_lock); 868ec52361dSNeilBrown serv->sv_nrthreads -= 1; 8692a36395fSNeilBrown spin_unlock_bh(&serv->sv_lock); 870ec52361dSNeilBrown svc_sock_update_bufs(serv); 871ec52361dSNeilBrown 8721b6dc1dfSJeff Layton svc_rqst_free(rqstp); 8731da177e4SLinus Torvalds 874ec52361dSNeilBrown svc_put(serv); 8751da177e4SLinus Torvalds } 87624c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_exit_thread); 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds /* 8792c7eb0b2SChuck Lever * Register an "inet" protocol family netid with the local 8802c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 881a26cfad6SChuck Lever * 8822c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8832c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 884a26cfad6SChuck Lever * 8852c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8862c7eb0b2SChuck Lever * if any error occurs. 8871da177e4SLinus Torvalds */ 8885247fab5SStanislav Kinsbursky static int __svc_rpcb_register4(struct net *net, const u32 program, 8895247fab5SStanislav Kinsbursky const u32 version, 890a26cfad6SChuck Lever const unsigned short protocol, 891a26cfad6SChuck Lever const unsigned short port) 892a26cfad6SChuck Lever { 893cadc0fa5SChuck Lever const struct sockaddr_in sin = { 894a26cfad6SChuck Lever .sin_family = AF_INET, 895a26cfad6SChuck Lever .sin_addr.s_addr = htonl(INADDR_ANY), 896a26cfad6SChuck Lever .sin_port = htons(port), 897a26cfad6SChuck Lever }; 898cadc0fa5SChuck Lever const char *netid; 899cadc0fa5SChuck Lever int error; 9002c7eb0b2SChuck Lever 9012c7eb0b2SChuck Lever switch (protocol) { 9022c7eb0b2SChuck Lever case IPPROTO_UDP: 9032c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP; 9042c7eb0b2SChuck Lever break; 9052c7eb0b2SChuck Lever case IPPROTO_TCP: 9062c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP; 9072c7eb0b2SChuck Lever break; 9082c7eb0b2SChuck Lever default: 909ba5c35e0SChuck Lever return -ENOPROTOOPT; 9102c7eb0b2SChuck Lever } 9112c7eb0b2SChuck Lever 9125247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 913cadc0fa5SChuck Lever (const struct sockaddr *)&sin, netid); 914cadc0fa5SChuck Lever 915cadc0fa5SChuck Lever /* 916cadc0fa5SChuck Lever * User space didn't support rpcbind v4, so retry this 917cadc0fa5SChuck Lever * registration request with the legacy rpcbind v2 protocol. 918cadc0fa5SChuck Lever */ 919cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 9205247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, protocol, port); 921cadc0fa5SChuck Lever 922cadc0fa5SChuck Lever return error; 9232c7eb0b2SChuck Lever } 9242c7eb0b2SChuck Lever 925dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 9262c7eb0b2SChuck Lever /* 9272c7eb0b2SChuck Lever * Register an "inet6" protocol family netid with the local 9282c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 9292c7eb0b2SChuck Lever * 9302c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 9312c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 9322c7eb0b2SChuck Lever * 9332c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 9342c7eb0b2SChuck Lever * if any error occurs. 9352c7eb0b2SChuck Lever */ 9365247fab5SStanislav Kinsbursky static int __svc_rpcb_register6(struct net *net, const u32 program, 9375247fab5SStanislav Kinsbursky const u32 version, 9382c7eb0b2SChuck Lever const unsigned short protocol, 9392c7eb0b2SChuck Lever const unsigned short port) 9402c7eb0b2SChuck Lever { 941cadc0fa5SChuck Lever const struct sockaddr_in6 sin6 = { 942a26cfad6SChuck Lever .sin6_family = AF_INET6, 943a26cfad6SChuck Lever .sin6_addr = IN6ADDR_ANY_INIT, 944a26cfad6SChuck Lever .sin6_port = htons(port), 945a26cfad6SChuck Lever }; 946cadc0fa5SChuck Lever const char *netid; 947cadc0fa5SChuck Lever int error; 948a26cfad6SChuck Lever 9492c7eb0b2SChuck Lever switch (protocol) { 9502c7eb0b2SChuck Lever case IPPROTO_UDP: 9512c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP6; 9522c7eb0b2SChuck Lever break; 9532c7eb0b2SChuck Lever case IPPROTO_TCP: 9542c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP6; 9552c7eb0b2SChuck Lever break; 9562c7eb0b2SChuck Lever default: 957ba5c35e0SChuck Lever return -ENOPROTOOPT; 9582c7eb0b2SChuck Lever } 9592c7eb0b2SChuck Lever 9605247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 961cadc0fa5SChuck Lever (const struct sockaddr *)&sin6, netid); 962cadc0fa5SChuck Lever 963cadc0fa5SChuck Lever /* 964cadc0fa5SChuck Lever * User space didn't support rpcbind version 4, so we won't 965cadc0fa5SChuck Lever * use a PF_INET6 listener. 966cadc0fa5SChuck Lever */ 967cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 968cadc0fa5SChuck Lever error = -EAFNOSUPPORT; 969cadc0fa5SChuck Lever 970cadc0fa5SChuck Lever return error; 9712c7eb0b2SChuck Lever } 972dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 9732c7eb0b2SChuck Lever 9742c7eb0b2SChuck Lever /* 9752c7eb0b2SChuck Lever * Register a kernel RPC service via rpcbind version 4. 9762c7eb0b2SChuck Lever * 9772c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 9782c7eb0b2SChuck Lever * if any error occurs. 9792c7eb0b2SChuck Lever */ 9805247fab5SStanislav Kinsbursky static int __svc_register(struct net *net, const char *progname, 981363f724cSChuck Lever const u32 program, const u32 version, 9824b62e58cSChuck Lever const int family, 9832c7eb0b2SChuck Lever const unsigned short protocol, 9842c7eb0b2SChuck Lever const unsigned short port) 9852c7eb0b2SChuck Lever { 986363f724cSChuck Lever int error = -EAFNOSUPPORT; 9872c7eb0b2SChuck Lever 988a26cfad6SChuck Lever switch (family) { 9894b62e58cSChuck Lever case PF_INET: 9905247fab5SStanislav Kinsbursky error = __svc_rpcb_register4(net, program, version, 9912c7eb0b2SChuck Lever protocol, port); 992cadc0fa5SChuck Lever break; 993dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 9944b62e58cSChuck Lever case PF_INET6: 9955247fab5SStanislav Kinsbursky error = __svc_rpcb_register6(net, program, version, 9962c7eb0b2SChuck Lever protocol, port); 997dfd56b8bSEric Dumazet #endif 9982c7eb0b2SChuck Lever } 9992c7eb0b2SChuck Lever 1000b4af5932SChuck Lever trace_svc_register(progname, version, protocol, port, family, error); 1001a26cfad6SChuck Lever return error; 1002a26cfad6SChuck Lever } 1003a26cfad6SChuck Lever 1004642ee6b2STrond Myklebust int svc_rpcbind_set_version(struct net *net, 1005642ee6b2STrond Myklebust const struct svc_program *progp, 1006642ee6b2STrond Myklebust u32 version, int family, 1007642ee6b2STrond Myklebust unsigned short proto, 1008642ee6b2STrond Myklebust unsigned short port) 1009642ee6b2STrond Myklebust { 1010642ee6b2STrond Myklebust return __svc_register(net, progp->pg_name, progp->pg_prog, 1011642ee6b2STrond Myklebust version, family, proto, port); 1012642ee6b2STrond Myklebust 1013642ee6b2STrond Myklebust } 1014642ee6b2STrond Myklebust EXPORT_SYMBOL_GPL(svc_rpcbind_set_version); 1015642ee6b2STrond Myklebust 1016642ee6b2STrond Myklebust int svc_generic_rpcbind_set(struct net *net, 1017642ee6b2STrond Myklebust const struct svc_program *progp, 1018642ee6b2STrond Myklebust u32 version, int family, 1019642ee6b2STrond Myklebust unsigned short proto, 1020642ee6b2STrond Myklebust unsigned short port) 1021642ee6b2STrond Myklebust { 1022642ee6b2STrond Myklebust const struct svc_version *vers = progp->pg_vers[version]; 1023642ee6b2STrond Myklebust int error; 1024642ee6b2STrond Myklebust 1025642ee6b2STrond Myklebust if (vers == NULL) 1026642ee6b2STrond Myklebust return 0; 1027642ee6b2STrond Myklebust 1028642ee6b2STrond Myklebust if (vers->vs_hidden) { 1029b4af5932SChuck Lever trace_svc_noregister(progp->pg_name, version, proto, 1030b4af5932SChuck Lever port, family, 0); 1031642ee6b2STrond Myklebust return 0; 1032642ee6b2STrond Myklebust } 1033642ee6b2STrond Myklebust 1034642ee6b2STrond Myklebust /* 1035642ee6b2STrond Myklebust * Don't register a UDP port if we need congestion 1036642ee6b2STrond Myklebust * control. 1037642ee6b2STrond Myklebust */ 1038642ee6b2STrond Myklebust if (vers->vs_need_cong_ctrl && proto == IPPROTO_UDP) 1039642ee6b2STrond Myklebust return 0; 1040642ee6b2STrond Myklebust 1041642ee6b2STrond Myklebust error = svc_rpcbind_set_version(net, progp, version, 1042642ee6b2STrond Myklebust family, proto, port); 1043642ee6b2STrond Myklebust 1044642ee6b2STrond Myklebust return (vers->vs_rpcb_optnl) ? 0 : error; 1045642ee6b2STrond Myklebust } 1046642ee6b2STrond Myklebust EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set); 1047642ee6b2STrond Myklebust 1048a26cfad6SChuck Lever /** 1049a26cfad6SChuck Lever * svc_register - register an RPC service with the local portmapper 1050a26cfad6SChuck Lever * @serv: svc_serv struct for the service to register 10515247fab5SStanislav Kinsbursky * @net: net namespace for the service to register 10524b62e58cSChuck Lever * @family: protocol family of service's listener socket 1053a26cfad6SChuck Lever * @proto: transport protocol number to advertise 1054a26cfad6SChuck Lever * @port: port to advertise 1055a26cfad6SChuck Lever * 10564b62e58cSChuck Lever * Service is registered for any address in the passed-in protocol family 1057a26cfad6SChuck Lever */ 10585247fab5SStanislav Kinsbursky int svc_register(const struct svc_serv *serv, struct net *net, 10595247fab5SStanislav Kinsbursky const int family, const unsigned short proto, 10605247fab5SStanislav Kinsbursky const unsigned short port) 10611da177e4SLinus Torvalds { 10621da177e4SLinus Torvalds struct svc_program *progp; 1063ea339d46SChuck Lever unsigned int i; 106414aeb211SChuck Lever int error = 0; 10651da177e4SLinus Torvalds 10660af39507SWeston Andros Adamson WARN_ON_ONCE(proto == 0 && port == 0); 10670af39507SWeston Andros Adamson if (proto == 0 && port == 0) 10680af39507SWeston Andros Adamson return -EINVAL; 10691da177e4SLinus Torvalds 1070bc5fea42SOlaf Kirch for (progp = serv->sv_program; progp; progp = progp->pg_next) { 10711da177e4SLinus Torvalds for (i = 0; i < progp->pg_nvers; i++) { 1072bc5fea42SOlaf Kirch 1073642ee6b2STrond Myklebust error = progp->pg_rpcbind_set(net, progp, i, 1074642ee6b2STrond Myklebust family, proto, port); 10757e55b59bSKinglong Mee if (error < 0) { 10767e55b59bSKinglong Mee printk(KERN_WARNING "svc: failed to register " 10777e55b59bSKinglong Mee "%sv%u RPC service (errno %d).\n", 10787e55b59bSKinglong Mee progp->pg_name, i, -error); 10791da177e4SLinus Torvalds break; 10801da177e4SLinus Torvalds } 1081bc5fea42SOlaf Kirch } 10827e55b59bSKinglong Mee } 10831da177e4SLinus Torvalds 10847252d575SChuck Lever return error; 10857252d575SChuck Lever } 10867252d575SChuck Lever 1087d5a8620fSChuck Lever /* 1088d5a8620fSChuck Lever * If user space is running rpcbind, it should take the v4 UNSET 1089d5a8620fSChuck Lever * and clear everything for this [program, version]. If user space 1090d5a8620fSChuck Lever * is running portmap, it will reject the v4 UNSET, but won't have 1091d5a8620fSChuck Lever * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient 1092d5a8620fSChuck Lever * in this case to clear all existing entries for [program, version]. 1093d5a8620fSChuck Lever */ 10945247fab5SStanislav Kinsbursky static void __svc_unregister(struct net *net, const u32 program, const u32 version, 1095f6fb3f6fSChuck Lever const char *progname) 1096f6fb3f6fSChuck Lever { 1097f6fb3f6fSChuck Lever int error; 1098f6fb3f6fSChuck Lever 10995247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, NULL, ""); 1100d5a8620fSChuck Lever 1101d5a8620fSChuck Lever /* 1102d5a8620fSChuck Lever * User space didn't support rpcbind v4, so retry this 1103d5a8620fSChuck Lever * request with the legacy rpcbind v2 protocol. 1104d5a8620fSChuck Lever */ 1105d5a8620fSChuck Lever if (error == -EPROTONOSUPPORT) 11065247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, 0, 0); 1107d5a8620fSChuck Lever 1108b4af5932SChuck Lever trace_svc_unregister(progname, version, error); 1109f6fb3f6fSChuck Lever } 1110f6fb3f6fSChuck Lever 11117252d575SChuck Lever /* 1112f6fb3f6fSChuck Lever * All netids, bind addresses and ports registered for [program, version] 1113f6fb3f6fSChuck Lever * are removed from the local rpcbind database (if the service is not 1114f6fb3f6fSChuck Lever * hidden) to make way for a new instance of the service. 11157252d575SChuck Lever * 1116f6fb3f6fSChuck Lever * The result of unregistration is reported via dprintk for those who want 1117f6fb3f6fSChuck Lever * verification of the result, but is otherwise not important. 11187252d575SChuck Lever */ 11195247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net) 11207252d575SChuck Lever { 11217252d575SChuck Lever struct svc_program *progp; 11227252d575SChuck Lever unsigned long flags; 11237252d575SChuck Lever unsigned int i; 11247252d575SChuck Lever 11257252d575SChuck Lever clear_thread_flag(TIF_SIGPENDING); 11267252d575SChuck Lever 11277252d575SChuck Lever for (progp = serv->sv_program; progp; progp = progp->pg_next) { 11287252d575SChuck Lever for (i = 0; i < progp->pg_nvers; i++) { 11297252d575SChuck Lever if (progp->pg_vers[i] == NULL) 11307252d575SChuck Lever continue; 11317252d575SChuck Lever if (progp->pg_vers[i]->vs_hidden) 11327252d575SChuck Lever continue; 11335247fab5SStanislav Kinsbursky __svc_unregister(net, progp->pg_prog, i, progp->pg_name); 11347252d575SChuck Lever } 11357252d575SChuck Lever } 11367252d575SChuck Lever 11371da177e4SLinus Torvalds spin_lock_irqsave(¤t->sighand->siglock, flags); 11381da177e4SLinus Torvalds recalc_sigpending(); 11391da177e4SLinus Torvalds spin_unlock_irqrestore(¤t->sighand->siglock, flags); 11401da177e4SLinus Torvalds } 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds /* 11437032a3ddSJ. Bruce Fields * dprintk the given error with the address of the client that caused it. 1144354ecbb9SDr. David Alan Gilbert */ 1145f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 1146b9075fa9SJoe Perches static __printf(2, 3) 1147e87cc472SJoe Perches void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) 1148354ecbb9SDr. David Alan Gilbert { 1149e87cc472SJoe Perches struct va_format vaf; 1150354ecbb9SDr. David Alan Gilbert va_list args; 1151354ecbb9SDr. David Alan Gilbert char buf[RPC_MAX_ADDRBUFLEN]; 1152354ecbb9SDr. David Alan Gilbert 1153354ecbb9SDr. David Alan Gilbert va_start(args, fmt); 1154354ecbb9SDr. David Alan Gilbert 1155e87cc472SJoe Perches vaf.fmt = fmt; 1156e87cc472SJoe Perches vaf.va = &args; 1157e87cc472SJoe Perches 11587032a3ddSJ. Bruce Fields dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); 1159e87cc472SJoe Perches 1160e87cc472SJoe Perches va_end(args); 1161354ecbb9SDr. David Alan Gilbert } 1162624ab464SJ. Bruce Fields #else 1163624ab464SJ. Bruce Fields static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} 1164624ab464SJ. Bruce Fields #endif 1165354ecbb9SDr. David Alan Gilbert 11668e5b6773STrond Myklebust __be32 11678e5b6773STrond Myklebust svc_generic_init_request(struct svc_rqst *rqstp, 11688e5b6773STrond Myklebust const struct svc_program *progp, 11698e5b6773STrond Myklebust struct svc_process_info *ret) 11708e5b6773STrond Myklebust { 11718e5b6773STrond Myklebust const struct svc_version *versp = NULL; /* compiler food */ 11728e5b6773STrond Myklebust const struct svc_procedure *procp = NULL; 11738e5b6773STrond Myklebust 11748e5b6773STrond Myklebust if (rqstp->rq_vers >= progp->pg_nvers ) 11758e5b6773STrond Myklebust goto err_bad_vers; 11768e5b6773STrond Myklebust versp = progp->pg_vers[rqstp->rq_vers]; 11778e5b6773STrond Myklebust if (!versp) 11788e5b6773STrond Myklebust goto err_bad_vers; 11798e5b6773STrond Myklebust 11808e5b6773STrond Myklebust /* 11818e5b6773STrond Myklebust * Some protocol versions (namely NFSv4) require some form of 11828e5b6773STrond Myklebust * congestion control. (See RFC 7530 section 3.1 paragraph 2) 11838e5b6773STrond Myklebust * In other words, UDP is not allowed. We mark those when setting 11848e5b6773STrond Myklebust * up the svc_xprt, and verify that here. 11858e5b6773STrond Myklebust * 11868e5b6773STrond Myklebust * The spec is not very clear about what error should be returned 11878e5b6773STrond Myklebust * when someone tries to access a server that is listening on UDP 11888e5b6773STrond Myklebust * for lower versions. RPC_PROG_MISMATCH seems to be the closest 11898e5b6773STrond Myklebust * fit. 11908e5b6773STrond Myklebust */ 11918e5b6773STrond Myklebust if (versp->vs_need_cong_ctrl && rqstp->rq_xprt && 11928e5b6773STrond Myklebust !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags)) 11938e5b6773STrond Myklebust goto err_bad_vers; 11948e5b6773STrond Myklebust 11958e5b6773STrond Myklebust if (rqstp->rq_proc >= versp->vs_nproc) 11968e5b6773STrond Myklebust goto err_bad_proc; 11978e5b6773STrond Myklebust rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc]; 11988e5b6773STrond Myklebust if (!procp) 11998e5b6773STrond Myklebust goto err_bad_proc; 12008e5b6773STrond Myklebust 12018e5b6773STrond Myklebust /* Initialize storage for argp and resp */ 12028e5b6773STrond Myklebust memset(rqstp->rq_argp, 0, procp->pc_argsize); 12038e5b6773STrond Myklebust memset(rqstp->rq_resp, 0, procp->pc_ressize); 12048e5b6773STrond Myklebust 12058e5b6773STrond Myklebust /* Bump per-procedure stats counter */ 12068e5b6773STrond Myklebust versp->vs_count[rqstp->rq_proc]++; 12078e5b6773STrond Myklebust 12088e5b6773STrond Myklebust ret->dispatch = versp->vs_dispatch; 12098e5b6773STrond Myklebust return rpc_success; 12108e5b6773STrond Myklebust err_bad_vers: 12118e5b6773STrond Myklebust ret->mismatch.lovers = progp->pg_lovers; 12128e5b6773STrond Myklebust ret->mismatch.hivers = progp->pg_hivers; 12138e5b6773STrond Myklebust return rpc_prog_mismatch; 12148e5b6773STrond Myklebust err_bad_proc: 12158e5b6773STrond Myklebust return rpc_proc_unavail; 12168e5b6773STrond Myklebust } 12178e5b6773STrond Myklebust EXPORT_SYMBOL_GPL(svc_generic_init_request); 12188e5b6773STrond Myklebust 1219354ecbb9SDr. David Alan Gilbert /* 12201cad7ea6SRicardo Labiaga * Common routine for processing the RPC request. 12211da177e4SLinus Torvalds */ 12221cad7ea6SRicardo Labiaga static int 12231cad7ea6SRicardo Labiaga svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) 12241da177e4SLinus Torvalds { 12251da177e4SLinus Torvalds struct svc_program *progp; 1226860bda29SChristoph Hellwig const struct svc_procedure *procp = NULL; 12276fb2b47fSNeilBrown struct svc_serv *serv = rqstp->rq_server; 12288e5b6773STrond Myklebust struct svc_process_info process; 1229d8ed029dSAlexey Dobriyan __be32 *statp; 12308e5b6773STrond Myklebust u32 prog, vers; 1231438623a0SChuck Lever __be32 rpc_stat; 12325b747a59SChuck Lever int auth_res, rc; 12338f8e05c5SJ.Bruce Fields __be32 *reply_statp; 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds rpc_stat = rpc_success; 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds if (argv->iov_len < 6*4) 12381da177e4SLinus Torvalds goto err_short_len; 12391da177e4SLinus Torvalds 124006eb8a56SChuck Lever /* Will be turned off by GSS integrity and privacy services */ 1241779fb0f3SJeff Layton set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); 12422f425878SAndy Adamson /* Will be turned off only when NFSv4 Sessions are used */ 124330660e04SJeff Layton set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); 124478b65eb3SJeff Layton clear_bit(RQ_DROPME, &rqstp->rq_flags); 1245e831fe65STom Tucker 12461da177e4SLinus Torvalds svc_putu32(resv, rqstp->rq_xid); 12471da177e4SLinus Torvalds 124876994313SAlexey Dobriyan vers = svc_getnl(argv); 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds /* First words of reply: */ 125176994313SAlexey Dobriyan svc_putnl(resv, 1); /* REPLY */ 12521da177e4SLinus Torvalds 12531da177e4SLinus Torvalds if (vers != 2) /* RPC version number */ 12541da177e4SLinus Torvalds goto err_bad_rpc; 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds /* Save position in case we later decide to reject: */ 12578f8e05c5SJ.Bruce Fields reply_statp = resv->iov_base + resv->iov_len; 12581da177e4SLinus Torvalds 125976994313SAlexey Dobriyan svc_putnl(resv, 0); /* ACCEPT */ 12601da177e4SLinus Torvalds 126176994313SAlexey Dobriyan rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ 12628e5b6773STrond Myklebust rqstp->rq_vers = svc_getnl(argv); /* version number */ 12638e5b6773STrond Myklebust rqstp->rq_proc = svc_getnl(argv); /* procedure number */ 12641da177e4SLinus Torvalds 126580d188a6SNeilBrown for (progp = serv->sv_program; progp; progp = progp->pg_next) 126680d188a6SNeilBrown if (prog == progp->pg_prog) 126780d188a6SNeilBrown break; 126880d188a6SNeilBrown 12691da177e4SLinus Torvalds /* 12701da177e4SLinus Torvalds * Decode auth data, and add verifier to reply buffer. 12711da177e4SLinus Torvalds * We do this before anything else in order to get a decent 12721da177e4SLinus Torvalds * auth verifier. 12731da177e4SLinus Torvalds */ 1274438623a0SChuck Lever auth_res = svc_authenticate(rqstp); 12751da177e4SLinus Torvalds /* Also give the program a chance to reject this call: */ 12765c2465dfSChuck Lever if (auth_res == SVC_OK && progp) 12771da177e4SLinus Torvalds auth_res = progp->pg_authenticate(rqstp); 1278ff27e9f7SChuck Lever if (auth_res != SVC_OK) 1279438623a0SChuck Lever trace_svc_authenticate(rqstp, auth_res); 12801da177e4SLinus Torvalds switch (auth_res) { 12811da177e4SLinus Torvalds case SVC_OK: 12821da177e4SLinus Torvalds break; 12831da177e4SLinus Torvalds case SVC_GARBAGE: 1284dd35210eSHarshula Jayasuriya goto err_garbage; 12851da177e4SLinus Torvalds case SVC_SYSERR: 12861da177e4SLinus Torvalds rpc_stat = rpc_system_err; 12871da177e4SLinus Torvalds goto err_bad; 12881da177e4SLinus Torvalds case SVC_DENIED: 12891da177e4SLinus Torvalds goto err_bad_auth; 12901ebede86SNeilBrown case SVC_CLOSE: 12914d712ef1SChuck Lever goto close; 12921da177e4SLinus Torvalds case SVC_DROP: 12931da177e4SLinus Torvalds goto dropit; 12941da177e4SLinus Torvalds case SVC_COMPLETE: 12951da177e4SLinus Torvalds goto sendit; 12961da177e4SLinus Torvalds } 12971da177e4SLinus Torvalds 12989ba02638SAndreas Gruenbacher if (progp == NULL) 12991da177e4SLinus Torvalds goto err_bad_prog; 13001da177e4SLinus Torvalds 13018e5b6773STrond Myklebust rpc_stat = progp->pg_init_request(rqstp, progp, &process); 13028e5b6773STrond Myklebust switch (rpc_stat) { 13038e5b6773STrond Myklebust case rpc_success: 13048e5b6773STrond Myklebust break; 13058e5b6773STrond Myklebust case rpc_prog_unavail: 13068e5b6773STrond Myklebust goto err_bad_prog; 13078e5b6773STrond Myklebust case rpc_prog_mismatch: 13081da177e4SLinus Torvalds goto err_bad_vers; 13098e5b6773STrond Myklebust case rpc_proc_unavail: 13101da177e4SLinus Torvalds goto err_bad_proc; 13118e5b6773STrond Myklebust } 13128e5b6773STrond Myklebust 13138e5b6773STrond Myklebust procp = rqstp->rq_procinfo; 13148e5b6773STrond Myklebust /* Should this check go into the dispatcher? */ 13158e5b6773STrond Myklebust if (!procp || !procp->pc_func) 13168e5b6773STrond Myklebust goto err_bad_proc; 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds /* Syntactic check complete */ 13191da177e4SLinus Torvalds serv->sv_stats->rpccnt++; 13200b9547bfSChuck Lever trace_svc_process(rqstp, progp->pg_name); 13211da177e4SLinus Torvalds 13221da177e4SLinus Torvalds /* Build the reply header. */ 13231da177e4SLinus Torvalds statp = resv->iov_base +resv->iov_len; 132476994313SAlexey Dobriyan svc_putnl(resv, RPC_SUCCESS); 13251da177e4SLinus Torvalds 13261da177e4SLinus Torvalds /* un-reserve some of the out-queue now that we have a 13271da177e4SLinus Torvalds * better idea of reply size 13281da177e4SLinus Torvalds */ 13291da177e4SLinus Torvalds if (procp->pc_xdrressize) 1330cd123012SJeff Layton svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds /* Call the function that processes the request. */ 13335b747a59SChuck Lever rc = process.dispatch(rqstp, statp); 13345b747a59SChuck Lever if (procp->pc_release) 13355b747a59SChuck Lever procp->pc_release(rqstp); 13365b747a59SChuck Lever if (!rc) 13375b747a59SChuck Lever goto dropit; 13389082e1d9SChuck Lever if (rqstp->rq_auth_stat != rpc_auth_ok) 13395b747a59SChuck Lever goto err_bad_auth; 13409082e1d9SChuck Lever 13411da177e4SLinus Torvalds /* Check RPC status result */ 13421da177e4SLinus Torvalds if (*statp != rpc_success) 13431da177e4SLinus Torvalds resv->iov_len = ((void*)statp) - resv->iov_base + 4; 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds if (procp->pc_encode == NULL) 13461da177e4SLinus Torvalds goto dropit; 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds sendit: 13491da177e4SLinus Torvalds if (svc_authorise(rqstp)) 1350f1442d63SDaniel Kobras goto close_xprt; 13511cad7ea6SRicardo Labiaga return 1; /* Caller can now send it */ 13521da177e4SLinus Torvalds 13531da177e4SLinus Torvalds dropit: 13541da177e4SLinus Torvalds svc_authorise(rqstp); /* doesn't hurt to call this twice */ 13551da177e4SLinus Torvalds dprintk("svc: svc_process dropit\n"); 13561da177e4SLinus Torvalds return 0; 13571da177e4SLinus Torvalds 13584d712ef1SChuck Lever close: 1359f1442d63SDaniel Kobras svc_authorise(rqstp); 1360f1442d63SDaniel Kobras close_xprt: 1361d4b09acfSVasily Averin if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) 13624355d767SChuck Lever svc_xprt_close(rqstp->rq_xprt); 13634d712ef1SChuck Lever dprintk("svc: svc_process close\n"); 13644d712ef1SChuck Lever return 0; 13654d712ef1SChuck Lever 13661da177e4SLinus Torvalds err_short_len: 13675b5e0928SAlexey Dobriyan svc_printk(rqstp, "short len %zd, dropping request\n", 1368354ecbb9SDr. David Alan Gilbert argv->iov_len); 1369f1442d63SDaniel Kobras goto close_xprt; 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds err_bad_rpc: 13721da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 137376994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 137476994313SAlexey Dobriyan svc_putnl(resv, 0); /* RPC_MISMATCH */ 137576994313SAlexey Dobriyan svc_putnl(resv, 2); /* Only RPCv2 supported */ 137676994313SAlexey Dobriyan svc_putnl(resv, 2); 13771da177e4SLinus Torvalds goto sendit; 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds err_bad_auth: 1380438623a0SChuck Lever dprintk("svc: authentication failed (%d)\n", 1381438623a0SChuck Lever be32_to_cpu(rqstp->rq_auth_stat)); 13821da177e4SLinus Torvalds serv->sv_stats->rpcbadauth++; 13831da177e4SLinus Torvalds /* Restore write pointer to location of accept status: */ 13848f8e05c5SJ.Bruce Fields xdr_ressize_check(rqstp, reply_statp); 138576994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 138676994313SAlexey Dobriyan svc_putnl(resv, 1); /* AUTH_ERROR */ 1387438623a0SChuck Lever svc_putu32(resv, rqstp->rq_auth_stat); /* status */ 13881da177e4SLinus Torvalds goto sendit; 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds err_bad_prog: 13919ba02638SAndreas Gruenbacher dprintk("svc: unknown program %d\n", prog); 13921da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 139376994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_UNAVAIL); 13941da177e4SLinus Torvalds goto sendit; 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds err_bad_vers: 1397354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", 13988e5b6773STrond Myklebust rqstp->rq_vers, rqstp->rq_prog, progp->pg_name); 139934e9a63bSNeilBrown 14001da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 140176994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_MISMATCH); 14028e5b6773STrond Myklebust svc_putnl(resv, process.mismatch.lovers); 14038e5b6773STrond Myklebust svc_putnl(resv, process.mismatch.hivers); 14041da177e4SLinus Torvalds goto sendit; 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds err_bad_proc: 14078e5b6773STrond Myklebust svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc); 140834e9a63bSNeilBrown 14091da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 141076994313SAlexey Dobriyan svc_putnl(resv, RPC_PROC_UNAVAIL); 14111da177e4SLinus Torvalds goto sendit; 14121da177e4SLinus Torvalds 14131da177e4SLinus Torvalds err_garbage: 1414354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "failed to decode args\n"); 141534e9a63bSNeilBrown 14161da177e4SLinus Torvalds rpc_stat = rpc_garbage_args; 14171da177e4SLinus Torvalds err_bad: 14181da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 141976994313SAlexey Dobriyan svc_putnl(resv, ntohl(rpc_stat)); 14201da177e4SLinus Torvalds goto sendit; 14211da177e4SLinus Torvalds } 14227adae489SGreg Banks 14237adae489SGreg Banks /* 14241cad7ea6SRicardo Labiaga * Process the RPC request. 14251cad7ea6SRicardo Labiaga */ 14261cad7ea6SRicardo Labiaga int 14271cad7ea6SRicardo Labiaga svc_process(struct svc_rqst *rqstp) 14281cad7ea6SRicardo Labiaga { 14291cad7ea6SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 14301cad7ea6SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 14311cad7ea6SRicardo Labiaga struct svc_serv *serv = rqstp->rq_server; 14321cad7ea6SRicardo Labiaga u32 dir; 14331cad7ea6SRicardo Labiaga 14343a126180SChuck Lever #if IS_ENABLED(CONFIG_FAIL_SUNRPC) 14353a126180SChuck Lever if (!fail_sunrpc.ignore_server_disconnect && 14363a126180SChuck Lever should_fail(&fail_sunrpc.attr, 1)) 14373a126180SChuck Lever svc_xprt_deferred_close(rqstp->rq_xprt); 14383a126180SChuck Lever #endif 14393a126180SChuck Lever 14401cad7ea6SRicardo Labiaga /* 14411cad7ea6SRicardo Labiaga * Setup response xdr_buf. 14421cad7ea6SRicardo Labiaga * Initially it has just one page 14431cad7ea6SRicardo Labiaga */ 1444afc59400SJ. Bruce Fields rqstp->rq_next_page = &rqstp->rq_respages[1]; 14451cad7ea6SRicardo Labiaga resv->iov_base = page_address(rqstp->rq_respages[0]); 14461cad7ea6SRicardo Labiaga resv->iov_len = 0; 14471cad7ea6SRicardo Labiaga rqstp->rq_res.pages = rqstp->rq_respages + 1; 14481cad7ea6SRicardo Labiaga rqstp->rq_res.len = 0; 14491cad7ea6SRicardo Labiaga rqstp->rq_res.page_base = 0; 14501cad7ea6SRicardo Labiaga rqstp->rq_res.page_len = 0; 14511cad7ea6SRicardo Labiaga rqstp->rq_res.buflen = PAGE_SIZE; 14521cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_base = NULL; 14531cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_len = 0; 14541cad7ea6SRicardo Labiaga 14551cad7ea6SRicardo Labiaga dir = svc_getnl(argv); 14561cad7ea6SRicardo Labiaga if (dir != 0) { 14571cad7ea6SRicardo Labiaga /* direction != CALL */ 14581cad7ea6SRicardo Labiaga svc_printk(rqstp, "bad direction %d, dropping request\n", dir); 14591cad7ea6SRicardo Labiaga serv->sv_stats->rpcbadfmt++; 1460860a0d9eSJeff Layton goto out_drop; 14611cad7ea6SRicardo Labiaga } 14621cad7ea6SRicardo Labiaga 14634b5b3ba1SAndy Adamson /* Returns 1 for send, 0 for drop */ 14640b9547bfSChuck Lever if (likely(svc_process_common(rqstp, argv, resv))) 14650b9547bfSChuck Lever return svc_send(rqstp); 1466860a0d9eSJeff Layton 1467860a0d9eSJeff Layton out_drop: 14684b5b3ba1SAndy Adamson svc_drop(rqstp); 14694b5b3ba1SAndy Adamson return 0; 14704b5b3ba1SAndy Adamson } 14713f87d5d6SChuck Lever EXPORT_SYMBOL_GPL(svc_process); 14721cad7ea6SRicardo Labiaga 14739e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL) 14744d6bbb62SRicardo Labiaga /* 14754d6bbb62SRicardo Labiaga * Process a backchannel RPC request that arrived over an existing 14764d6bbb62SRicardo Labiaga * outbound connection 14774d6bbb62SRicardo Labiaga */ 14784d6bbb62SRicardo Labiaga int 14794d6bbb62SRicardo Labiaga bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, 14804d6bbb62SRicardo Labiaga struct svc_rqst *rqstp) 14814d6bbb62SRicardo Labiaga { 14824d6bbb62SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 14834d6bbb62SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 1484632dda83SChuck Lever struct rpc_task *task; 14850d2a970dSTrond Myklebust int proc_error; 1486632dda83SChuck Lever int error; 1487632dda83SChuck Lever 1488632dda83SChuck Lever dprintk("svc: %s(%p)\n", __func__, req); 14894d6bbb62SRicardo Labiaga 14904d6bbb62SRicardo Labiaga /* Build the svc_rqst used by the common processing routine */ 14914d6bbb62SRicardo Labiaga rqstp->rq_xid = req->rq_xid; 14924d6bbb62SRicardo Labiaga rqstp->rq_prot = req->rq_xprt->prot; 14934d6bbb62SRicardo Labiaga rqstp->rq_server = serv; 1494d4b09acfSVasily Averin rqstp->rq_bc_net = req->rq_xprt->xprt_net; 14954d6bbb62SRicardo Labiaga 14964d6bbb62SRicardo Labiaga rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); 14974d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); 14984d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); 14994d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); 1500756b9b37STrond Myklebust 1501756b9b37STrond Myklebust /* Adjust the argument buffer length */ 150238b7631fSBenjamin Coddington rqstp->rq_arg.len = req->rq_private_buf.len; 1503756b9b37STrond Myklebust if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { 1504756b9b37STrond Myklebust rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; 1505756b9b37STrond Myklebust rqstp->rq_arg.page_len = 0; 1506756b9b37STrond Myklebust } else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len + 1507756b9b37STrond Myklebust rqstp->rq_arg.page_len) 1508756b9b37STrond Myklebust rqstp->rq_arg.page_len = rqstp->rq_arg.len - 1509756b9b37STrond Myklebust rqstp->rq_arg.head[0].iov_len; 1510756b9b37STrond Myklebust else 1511756b9b37STrond Myklebust rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len + 1512756b9b37STrond Myklebust rqstp->rq_arg.page_len; 15134d6bbb62SRicardo Labiaga 15144d6bbb62SRicardo Labiaga /* reset result send buffer "put" position */ 15154d6bbb62SRicardo Labiaga resv->iov_len = 0; 15164d6bbb62SRicardo Labiaga 15174d6bbb62SRicardo Labiaga /* 15184d6bbb62SRicardo Labiaga * Skip the next two words because they've already been 1519632dda83SChuck Lever * processed in the transport 15204d6bbb62SRicardo Labiaga */ 15214d6bbb62SRicardo Labiaga svc_getu32(argv); /* XID */ 15224d6bbb62SRicardo Labiaga svc_getnl(argv); /* CALLDIR */ 15234d6bbb62SRicardo Labiaga 1524632dda83SChuck Lever /* Parse and execute the bc call */ 15250d2a970dSTrond Myklebust proc_error = svc_process_common(rqstp, argv, resv); 15260d2a970dSTrond Myklebust 15277402a4feSTrond Myklebust atomic_dec(&req->rq_xprt->bc_slot_count); 15280d2a970dSTrond Myklebust if (!proc_error) { 1529632dda83SChuck Lever /* Processing error: drop the request */ 1530b3b02ae5STrond Myklebust xprt_free_bc_request(req); 15318f7766c8SVasily Averin error = -EINVAL; 15328f7766c8SVasily Averin goto out; 15334b5b3ba1SAndy Adamson } 1534632dda83SChuck Lever /* Finally, send the reply synchronously */ 1535632dda83SChuck Lever memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); 15360f419791STrond Myklebust task = rpc_run_bc_task(req); 1537632dda83SChuck Lever if (IS_ERR(task)) { 1538632dda83SChuck Lever error = PTR_ERR(task); 1539632dda83SChuck Lever goto out; 1540632dda83SChuck Lever } 1541632dda83SChuck Lever 1542632dda83SChuck Lever WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); 1543632dda83SChuck Lever error = task->tk_status; 1544632dda83SChuck Lever rpc_put_task(task); 1545632dda83SChuck Lever 1546632dda83SChuck Lever out: 1547632dda83SChuck Lever dprintk("svc: %s(), error=%d\n", __func__, error); 1548632dda83SChuck Lever return error; 15494d6bbb62SRicardo Labiaga } 15500d961aa9STrond Myklebust EXPORT_SYMBOL_GPL(bc_svc_process); 15519e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */ 15524d6bbb62SRicardo Labiaga 15531cad7ea6SRicardo Labiaga /* 15547adae489SGreg Banks * Return (transport-specific) limit on the rpc payload. 15557adae489SGreg Banks */ 15567adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp) 15577adae489SGreg Banks { 155849023155STom Tucker u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload; 15597adae489SGreg Banks 1560c6b0a9f8SNeilBrown if (rqstp->rq_server->sv_max_payload < max) 1561c6b0a9f8SNeilBrown max = rqstp->rq_server->sv_max_payload; 15627adae489SGreg Banks return max; 15637adae489SGreg Banks } 15647adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload); 15658154ef27SChuck Lever 15668154ef27SChuck Lever /** 15675c117207SChuck Lever * svc_proc_name - Return RPC procedure name in string form 15685c117207SChuck Lever * @rqstp: svc_rqst to operate on 15695c117207SChuck Lever * 15705c117207SChuck Lever * Return value: 15715c117207SChuck Lever * Pointer to a NUL-terminated string 15725c117207SChuck Lever */ 15735c117207SChuck Lever const char *svc_proc_name(const struct svc_rqst *rqstp) 15745c117207SChuck Lever { 15755c117207SChuck Lever if (rqstp && rqstp->rq_procinfo) 15765c117207SChuck Lever return rqstp->rq_procinfo->pc_name; 15775c117207SChuck Lever return "unknown"; 15785c117207SChuck Lever } 15795c117207SChuck Lever 15805c117207SChuck Lever 15815c117207SChuck Lever /** 158203493bcaSChuck Lever * svc_encode_result_payload - mark a range of bytes as a result payload 158341205539SChuck Lever * @rqstp: svc_rqst to operate on 158441205539SChuck Lever * @offset: payload's byte offset in rqstp->rq_res 158541205539SChuck Lever * @length: size of payload, in bytes 158641205539SChuck Lever * 158741205539SChuck Lever * Returns zero on success, or a negative errno if a permanent 158841205539SChuck Lever * error occurred. 158941205539SChuck Lever */ 159003493bcaSChuck Lever int svc_encode_result_payload(struct svc_rqst *rqstp, unsigned int offset, 159141205539SChuck Lever unsigned int length) 159241205539SChuck Lever { 159303493bcaSChuck Lever return rqstp->rq_xprt->xpt_ops->xpo_result_payload(rqstp, offset, 159403493bcaSChuck Lever length); 159541205539SChuck Lever } 159603493bcaSChuck Lever EXPORT_SYMBOL_GPL(svc_encode_result_payload); 159741205539SChuck Lever 159841205539SChuck Lever /** 15998154ef27SChuck Lever * svc_fill_write_vector - Construct data argument for VFS write call 16008154ef27SChuck Lever * @rqstp: svc_rqst to operate on 1601dae9a6caSChuck Lever * @payload: xdr_buf containing only the write data payload 16028154ef27SChuck Lever * 16033fd9557aSChuck Lever * Fills in rqstp::rq_vec, and returns the number of elements. 16048154ef27SChuck Lever */ 1605dae9a6caSChuck Lever unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, 1606dae9a6caSChuck Lever struct xdr_buf *payload) 16078154ef27SChuck Lever { 1608dae9a6caSChuck Lever struct page **pages = payload->pages; 1609dae9a6caSChuck Lever struct kvec *first = payload->head; 16108154ef27SChuck Lever struct kvec *vec = rqstp->rq_vec; 1611dae9a6caSChuck Lever size_t total = payload->len; 16128154ef27SChuck Lever unsigned int i; 16138154ef27SChuck Lever 16148154ef27SChuck Lever /* Some types of transport can present the write payload 16158154ef27SChuck Lever * entirely in rq_arg.pages. In this case, @first is empty. 16168154ef27SChuck Lever */ 16178154ef27SChuck Lever i = 0; 16188154ef27SChuck Lever if (first->iov_len) { 16198154ef27SChuck Lever vec[i].iov_base = first->iov_base; 16208154ef27SChuck Lever vec[i].iov_len = min_t(size_t, total, first->iov_len); 16218154ef27SChuck Lever total -= vec[i].iov_len; 16228154ef27SChuck Lever ++i; 16238154ef27SChuck Lever } 16248154ef27SChuck Lever 16258154ef27SChuck Lever while (total) { 16268154ef27SChuck Lever vec[i].iov_base = page_address(*pages); 16278154ef27SChuck Lever vec[i].iov_len = min_t(size_t, total, PAGE_SIZE); 16288154ef27SChuck Lever total -= vec[i].iov_len; 16298154ef27SChuck Lever ++i; 16308154ef27SChuck Lever ++pages; 16318154ef27SChuck Lever } 16328154ef27SChuck Lever 16338154ef27SChuck Lever WARN_ON_ONCE(i > ARRAY_SIZE(rqstp->rq_vec)); 16348154ef27SChuck Lever return i; 16358154ef27SChuck Lever } 16368154ef27SChuck Lever EXPORT_SYMBOL_GPL(svc_fill_write_vector); 163738a70315SChuck Lever 163838a70315SChuck Lever /** 163938a70315SChuck Lever * svc_fill_symlink_pathname - Construct pathname argument for VFS symlink call 164038a70315SChuck Lever * @rqstp: svc_rqst to operate on 164138a70315SChuck Lever * @first: buffer containing first section of pathname 164211b4d66eSChuck Lever * @p: buffer containing remaining section of pathname 164338a70315SChuck Lever * @total: total length of the pathname argument 164438a70315SChuck Lever * 164511b4d66eSChuck Lever * The VFS symlink API demands a NUL-terminated pathname in mapped memory. 164611b4d66eSChuck Lever * Returns pointer to a NUL-terminated string, or an ERR_PTR. Caller must free 164711b4d66eSChuck Lever * the returned string. 164838a70315SChuck Lever */ 164938a70315SChuck Lever char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, struct kvec *first, 165011b4d66eSChuck Lever void *p, size_t total) 165138a70315SChuck Lever { 165238a70315SChuck Lever size_t len, remaining; 165311b4d66eSChuck Lever char *result, *dst; 165438a70315SChuck Lever 165511b4d66eSChuck Lever result = kmalloc(total + 1, GFP_KERNEL); 165611b4d66eSChuck Lever if (!result) 165711b4d66eSChuck Lever return ERR_PTR(-ESERVERFAULT); 165811b4d66eSChuck Lever 165938a70315SChuck Lever dst = result; 166038a70315SChuck Lever remaining = total; 166138a70315SChuck Lever 166238a70315SChuck Lever len = min_t(size_t, total, first->iov_len); 166311b4d66eSChuck Lever if (len) { 166438a70315SChuck Lever memcpy(dst, first->iov_base, len); 166538a70315SChuck Lever dst += len; 166638a70315SChuck Lever remaining -= len; 166711b4d66eSChuck Lever } 166838a70315SChuck Lever 166938a70315SChuck Lever if (remaining) { 167038a70315SChuck Lever len = min_t(size_t, remaining, PAGE_SIZE); 167111b4d66eSChuck Lever memcpy(dst, p, len); 167238a70315SChuck Lever dst += len; 167338a70315SChuck Lever } 167438a70315SChuck Lever 167538a70315SChuck Lever *dst = '\0'; 167638a70315SChuck Lever 167711b4d66eSChuck Lever /* Sanity check: Linux doesn't allow the pathname argument to 167838a70315SChuck Lever * contain a NUL byte. 167938a70315SChuck Lever */ 168011b4d66eSChuck Lever if (strlen(result) != total) { 168111b4d66eSChuck Lever kfree(result); 168238a70315SChuck Lever return ERR_PTR(-EINVAL); 168311b4d66eSChuck Lever } 168438a70315SChuck Lever return result; 168538a70315SChuck Lever } 168638a70315SChuck Lever EXPORT_SYMBOL_GPL(svc_fill_symlink_pathname); 1687