11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/net/sunrpc/svc.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * High-level RPC service routines 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 7bfd24160SGreg Banks * 8bfd24160SGreg Banks * Multiple threads pools and NUMAisation 9bfd24160SGreg Banks * Copyright (c) 2006 Silicon Graphics, Inc. 10bfd24160SGreg Banks * by Greg Banks <gnb@melbourne.sgi.com> 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <linux/linkage.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/errno.h> 161da177e4SLinus Torvalds #include <linux/net.h> 171da177e4SLinus Torvalds #include <linux/in.h> 181da177e4SLinus Torvalds #include <linux/mm.h> 19a7455442SGreg Banks #include <linux/interrupt.h> 20a7455442SGreg Banks #include <linux/module.h> 219867d76cSJeff Layton #include <linux/kthread.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <linux/sunrpc/types.h> 251da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h> 261da177e4SLinus Torvalds #include <linux/sunrpc/stats.h> 271da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h> 281da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 294d6bbb62SRicardo Labiaga #include <linux/sunrpc/bc_xprt.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #define RPCDBG_FACILITY RPCDBG_SVCDSP 321da177e4SLinus Torvalds 335247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net); 347252d575SChuck Lever 3542a7fc4aSGreg Banks #define svc_serv_is_pooled(serv) ((serv)->sv_function) 3642a7fc4aSGreg Banks 371da177e4SLinus Torvalds /* 38bfd24160SGreg Banks * Mode for mapping cpus to pools. 39bfd24160SGreg Banks */ 40bfd24160SGreg Banks enum { 4142a7fc4aSGreg Banks SVC_POOL_AUTO = -1, /* choose one of the others */ 42bfd24160SGreg Banks SVC_POOL_GLOBAL, /* no mapping, just a single global pool 43bfd24160SGreg Banks * (legacy & UP mode) */ 44bfd24160SGreg Banks SVC_POOL_PERCPU, /* one pool per cpu */ 45bfd24160SGreg Banks SVC_POOL_PERNODE /* one pool per numa node */ 46bfd24160SGreg Banks }; 4742a7fc4aSGreg Banks #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL 48bfd24160SGreg Banks 49bfd24160SGreg Banks /* 50bfd24160SGreg Banks * Structure for mapping cpus to pools and vice versa. 51bfd24160SGreg Banks * Setup once during sunrpc initialisation. 52bfd24160SGreg Banks */ 53bfd24160SGreg Banks static struct svc_pool_map { 5442a7fc4aSGreg Banks int count; /* How many svc_servs use us */ 55bfd24160SGreg Banks int mode; /* Note: int not enum to avoid 56bfd24160SGreg Banks * warnings about "enumeration value 57bfd24160SGreg Banks * not handled in switch" */ 58bfd24160SGreg Banks unsigned int npools; 59bfd24160SGreg Banks unsigned int *pool_to; /* maps pool id to cpu or node */ 60bfd24160SGreg Banks unsigned int *to_pool; /* maps cpu or node to pool id */ 61bfd24160SGreg Banks } svc_pool_map = { 6242a7fc4aSGreg Banks .count = 0, 6342a7fc4aSGreg Banks .mode = SVC_POOL_DEFAULT 64bfd24160SGreg Banks }; 6542a7fc4aSGreg Banks static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ 66bfd24160SGreg Banks 6742a7fc4aSGreg Banks static int 6842a7fc4aSGreg Banks param_set_pool_mode(const char *val, struct kernel_param *kp) 6942a7fc4aSGreg Banks { 7042a7fc4aSGreg Banks int *ip = (int *)kp->arg; 7142a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 7242a7fc4aSGreg Banks int err; 7342a7fc4aSGreg Banks 7442a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 7542a7fc4aSGreg Banks 7642a7fc4aSGreg Banks err = -EBUSY; 7742a7fc4aSGreg Banks if (m->count) 7842a7fc4aSGreg Banks goto out; 7942a7fc4aSGreg Banks 8042a7fc4aSGreg Banks err = 0; 8142a7fc4aSGreg Banks if (!strncmp(val, "auto", 4)) 8242a7fc4aSGreg Banks *ip = SVC_POOL_AUTO; 8342a7fc4aSGreg Banks else if (!strncmp(val, "global", 6)) 8442a7fc4aSGreg Banks *ip = SVC_POOL_GLOBAL; 8542a7fc4aSGreg Banks else if (!strncmp(val, "percpu", 6)) 8642a7fc4aSGreg Banks *ip = SVC_POOL_PERCPU; 8742a7fc4aSGreg Banks else if (!strncmp(val, "pernode", 7)) 8842a7fc4aSGreg Banks *ip = SVC_POOL_PERNODE; 8942a7fc4aSGreg Banks else 9042a7fc4aSGreg Banks err = -EINVAL; 9142a7fc4aSGreg Banks 9242a7fc4aSGreg Banks out: 9342a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 9442a7fc4aSGreg Banks return err; 9542a7fc4aSGreg Banks } 9642a7fc4aSGreg Banks 9742a7fc4aSGreg Banks static int 9842a7fc4aSGreg Banks param_get_pool_mode(char *buf, struct kernel_param *kp) 9942a7fc4aSGreg Banks { 10042a7fc4aSGreg Banks int *ip = (int *)kp->arg; 10142a7fc4aSGreg Banks 10242a7fc4aSGreg Banks switch (*ip) 10342a7fc4aSGreg Banks { 10442a7fc4aSGreg Banks case SVC_POOL_AUTO: 10542a7fc4aSGreg Banks return strlcpy(buf, "auto", 20); 10642a7fc4aSGreg Banks case SVC_POOL_GLOBAL: 10742a7fc4aSGreg Banks return strlcpy(buf, "global", 20); 10842a7fc4aSGreg Banks case SVC_POOL_PERCPU: 10942a7fc4aSGreg Banks return strlcpy(buf, "percpu", 20); 11042a7fc4aSGreg Banks case SVC_POOL_PERNODE: 11142a7fc4aSGreg Banks return strlcpy(buf, "pernode", 20); 11242a7fc4aSGreg Banks default: 11342a7fc4aSGreg Banks return sprintf(buf, "%d", *ip); 11442a7fc4aSGreg Banks } 11542a7fc4aSGreg Banks } 11642a7fc4aSGreg Banks 11742a7fc4aSGreg Banks module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode, 11842a7fc4aSGreg Banks &svc_pool_map.mode, 0644); 119bfd24160SGreg Banks 120bfd24160SGreg Banks /* 121bfd24160SGreg Banks * Detect best pool mapping mode heuristically, 122bfd24160SGreg Banks * according to the machine's topology. 123bfd24160SGreg Banks */ 124bfd24160SGreg Banks static int 125bfd24160SGreg Banks svc_pool_map_choose_mode(void) 126bfd24160SGreg Banks { 127bfd24160SGreg Banks unsigned int node; 128bfd24160SGreg Banks 12962bc62a8SChristoph Lameter if (nr_online_nodes > 1) { 130bfd24160SGreg Banks /* 131bfd24160SGreg Banks * Actually have multiple NUMA nodes, 132bfd24160SGreg Banks * so split pools on NUMA node boundaries 133bfd24160SGreg Banks */ 134bfd24160SGreg Banks return SVC_POOL_PERNODE; 135bfd24160SGreg Banks } 136bfd24160SGreg Banks 13772c33688SH Hartley Sweeten node = first_online_node; 138bfd24160SGreg Banks if (nr_cpus_node(node) > 2) { 139bfd24160SGreg Banks /* 140bfd24160SGreg Banks * Non-trivial SMP, or CONFIG_NUMA on 141bfd24160SGreg Banks * non-NUMA hardware, e.g. with a generic 142bfd24160SGreg Banks * x86_64 kernel on Xeons. In this case we 143bfd24160SGreg Banks * want to divide the pools on cpu boundaries. 144bfd24160SGreg Banks */ 145bfd24160SGreg Banks return SVC_POOL_PERCPU; 146bfd24160SGreg Banks } 147bfd24160SGreg Banks 148bfd24160SGreg Banks /* default: one global pool */ 149bfd24160SGreg Banks return SVC_POOL_GLOBAL; 150bfd24160SGreg Banks } 151bfd24160SGreg Banks 152bfd24160SGreg Banks /* 153bfd24160SGreg Banks * Allocate the to_pool[] and pool_to[] arrays. 154bfd24160SGreg Banks * Returns 0 on success or an errno. 155bfd24160SGreg Banks */ 156bfd24160SGreg Banks static int 157bfd24160SGreg Banks svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) 158bfd24160SGreg Banks { 159bfd24160SGreg Banks m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 160bfd24160SGreg Banks if (!m->to_pool) 161bfd24160SGreg Banks goto fail; 162bfd24160SGreg Banks m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 163bfd24160SGreg Banks if (!m->pool_to) 164bfd24160SGreg Banks goto fail_free; 165bfd24160SGreg Banks 166bfd24160SGreg Banks return 0; 167bfd24160SGreg Banks 168bfd24160SGreg Banks fail_free: 169bfd24160SGreg Banks kfree(m->to_pool); 17061c8504cSJ. Bruce Fields m->to_pool = NULL; 171bfd24160SGreg Banks fail: 172bfd24160SGreg Banks return -ENOMEM; 173bfd24160SGreg Banks } 174bfd24160SGreg Banks 175bfd24160SGreg Banks /* 176bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERCPU mode. 177bfd24160SGreg Banks * Returns number of pools or <0 on error. 178bfd24160SGreg Banks */ 179bfd24160SGreg Banks static int 180bfd24160SGreg Banks svc_pool_map_init_percpu(struct svc_pool_map *m) 181bfd24160SGreg Banks { 18253b8a315SChristoph Lameter unsigned int maxpools = nr_cpu_ids; 183bfd24160SGreg Banks unsigned int pidx = 0; 184bfd24160SGreg Banks unsigned int cpu; 185bfd24160SGreg Banks int err; 186bfd24160SGreg Banks 187bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 188bfd24160SGreg Banks if (err) 189bfd24160SGreg Banks return err; 190bfd24160SGreg Banks 191bfd24160SGreg Banks for_each_online_cpu(cpu) { 192bfd24160SGreg Banks BUG_ON(pidx > maxpools); 193bfd24160SGreg Banks m->to_pool[cpu] = pidx; 194bfd24160SGreg Banks m->pool_to[pidx] = cpu; 195bfd24160SGreg Banks pidx++; 196bfd24160SGreg Banks } 197bfd24160SGreg Banks /* cpus brought online later all get mapped to pool0, sorry */ 198bfd24160SGreg Banks 199bfd24160SGreg Banks return pidx; 200bfd24160SGreg Banks }; 201bfd24160SGreg Banks 202bfd24160SGreg Banks 203bfd24160SGreg Banks /* 204bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERNODE mode. 205bfd24160SGreg Banks * Returns number of pools or <0 on error. 206bfd24160SGreg Banks */ 207bfd24160SGreg Banks static int 208bfd24160SGreg Banks svc_pool_map_init_pernode(struct svc_pool_map *m) 209bfd24160SGreg Banks { 21074c7aa8bSChristoph Lameter unsigned int maxpools = nr_node_ids; 211bfd24160SGreg Banks unsigned int pidx = 0; 212bfd24160SGreg Banks unsigned int node; 213bfd24160SGreg Banks int err; 214bfd24160SGreg Banks 215bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 216bfd24160SGreg Banks if (err) 217bfd24160SGreg Banks return err; 218bfd24160SGreg Banks 219bfd24160SGreg Banks for_each_node_with_cpus(node) { 220bfd24160SGreg Banks /* some architectures (e.g. SN2) have cpuless nodes */ 221bfd24160SGreg Banks BUG_ON(pidx > maxpools); 222bfd24160SGreg Banks m->to_pool[node] = pidx; 223bfd24160SGreg Banks m->pool_to[pidx] = node; 224bfd24160SGreg Banks pidx++; 225bfd24160SGreg Banks } 226bfd24160SGreg Banks /* nodes brought online later all get mapped to pool0, sorry */ 227bfd24160SGreg Banks 228bfd24160SGreg Banks return pidx; 229bfd24160SGreg Banks } 230bfd24160SGreg Banks 231bfd24160SGreg Banks 232bfd24160SGreg Banks /* 23342a7fc4aSGreg Banks * Add a reference to the global map of cpus to pools (and 23442a7fc4aSGreg Banks * vice versa). Initialise the map if we're the first user. 23542a7fc4aSGreg Banks * Returns the number of pools. 236bfd24160SGreg Banks */ 237bfd24160SGreg Banks static unsigned int 23842a7fc4aSGreg Banks svc_pool_map_get(void) 239bfd24160SGreg Banks { 240bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 241bfd24160SGreg Banks int npools = -1; 242bfd24160SGreg Banks 24342a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 244bfd24160SGreg Banks 24542a7fc4aSGreg Banks if (m->count++) { 24642a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 24742a7fc4aSGreg Banks return m->npools; 24842a7fc4aSGreg Banks } 24942a7fc4aSGreg Banks 25042a7fc4aSGreg Banks if (m->mode == SVC_POOL_AUTO) 251bfd24160SGreg Banks m->mode = svc_pool_map_choose_mode(); 252bfd24160SGreg Banks 253bfd24160SGreg Banks switch (m->mode) { 254bfd24160SGreg Banks case SVC_POOL_PERCPU: 255bfd24160SGreg Banks npools = svc_pool_map_init_percpu(m); 256bfd24160SGreg Banks break; 257bfd24160SGreg Banks case SVC_POOL_PERNODE: 258bfd24160SGreg Banks npools = svc_pool_map_init_pernode(m); 259bfd24160SGreg Banks break; 260bfd24160SGreg Banks } 261bfd24160SGreg Banks 262bfd24160SGreg Banks if (npools < 0) { 263bfd24160SGreg Banks /* default, or memory allocation failure */ 264bfd24160SGreg Banks npools = 1; 265bfd24160SGreg Banks m->mode = SVC_POOL_GLOBAL; 266bfd24160SGreg Banks } 267bfd24160SGreg Banks m->npools = npools; 268bfd24160SGreg Banks 26942a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 270bfd24160SGreg Banks return m->npools; 271bfd24160SGreg Banks } 272bfd24160SGreg Banks 27342a7fc4aSGreg Banks 27442a7fc4aSGreg Banks /* 27542a7fc4aSGreg Banks * Drop a reference to the global map of cpus to pools. 27642a7fc4aSGreg Banks * When the last reference is dropped, the map data is 27742a7fc4aSGreg Banks * freed; this allows the sysadmin to change the pool 27842a7fc4aSGreg Banks * mode using the pool_mode module option without 27942a7fc4aSGreg Banks * rebooting or re-loading sunrpc.ko. 28042a7fc4aSGreg Banks */ 28142a7fc4aSGreg Banks static void 28242a7fc4aSGreg Banks svc_pool_map_put(void) 28342a7fc4aSGreg Banks { 28442a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 28542a7fc4aSGreg Banks 28642a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 28742a7fc4aSGreg Banks 28842a7fc4aSGreg Banks if (!--m->count) { 28942a7fc4aSGreg Banks kfree(m->to_pool); 29061c8504cSJ. Bruce Fields m->to_pool = NULL; 29142a7fc4aSGreg Banks kfree(m->pool_to); 29261c8504cSJ. Bruce Fields m->pool_to = NULL; 29342a7fc4aSGreg Banks m->npools = 0; 29442a7fc4aSGreg Banks } 29542a7fc4aSGreg Banks 29642a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 29742a7fc4aSGreg Banks } 29842a7fc4aSGreg Banks 29942a7fc4aSGreg Banks 30011fd165cSEric Dumazet static int svc_pool_map_get_node(unsigned int pidx) 30111fd165cSEric Dumazet { 30211fd165cSEric Dumazet const struct svc_pool_map *m = &svc_pool_map; 30311fd165cSEric Dumazet 30411fd165cSEric Dumazet if (m->count) { 30511fd165cSEric Dumazet if (m->mode == SVC_POOL_PERCPU) 30611fd165cSEric Dumazet return cpu_to_node(m->pool_to[pidx]); 30711fd165cSEric Dumazet if (m->mode == SVC_POOL_PERNODE) 30811fd165cSEric Dumazet return m->pool_to[pidx]; 30911fd165cSEric Dumazet } 31011fd165cSEric Dumazet return NUMA_NO_NODE; 31111fd165cSEric Dumazet } 312bfd24160SGreg Banks /* 3139867d76cSJeff Layton * Set the given thread's cpus_allowed mask so that it 314bfd24160SGreg Banks * will only run on cpus in the given pool. 315bfd24160SGreg Banks */ 3169867d76cSJeff Layton static inline void 3179867d76cSJeff Layton svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) 318bfd24160SGreg Banks { 319bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 3209867d76cSJeff Layton unsigned int node = m->pool_to[pidx]; 321bfd24160SGreg Banks 322bfd24160SGreg Banks /* 323bfd24160SGreg Banks * The caller checks for sv_nrpools > 1, which 32442a7fc4aSGreg Banks * implies that we've been initialized. 325bfd24160SGreg Banks */ 3261bd58aafSWeston Andros Adamson WARN_ON_ONCE(m->count == 0); 3271bd58aafSWeston Andros Adamson if (m->count == 0) 3281bd58aafSWeston Andros Adamson return; 329bfd24160SGreg Banks 3309867d76cSJeff Layton switch (m->mode) { 331bfd24160SGreg Banks case SVC_POOL_PERCPU: 332c5f59f08SMike Travis { 333aa85ea5bSRusty Russell set_cpus_allowed_ptr(task, cpumask_of(node)); 3349867d76cSJeff Layton break; 335c5f59f08SMike Travis } 336bfd24160SGreg Banks case SVC_POOL_PERNODE: 337c5f59f08SMike Travis { 338a70f7302SRusty Russell set_cpus_allowed_ptr(task, cpumask_of_node(node)); 3399867d76cSJeff Layton break; 340bfd24160SGreg Banks } 341bfd24160SGreg Banks } 342c5f59f08SMike Travis } 343bfd24160SGreg Banks 344bfd24160SGreg Banks /* 345bfd24160SGreg Banks * Use the mapping mode to choose a pool for a given CPU. 346bfd24160SGreg Banks * Used when enqueueing an incoming RPC. Always returns 347bfd24160SGreg Banks * a non-NULL pool pointer. 348bfd24160SGreg Banks */ 349bfd24160SGreg Banks struct svc_pool * 350bfd24160SGreg Banks svc_pool_for_cpu(struct svc_serv *serv, int cpu) 351bfd24160SGreg Banks { 352bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 353bfd24160SGreg Banks unsigned int pidx = 0; 354bfd24160SGreg Banks 355bfd24160SGreg Banks /* 35642a7fc4aSGreg Banks * An uninitialised map happens in a pure client when 357bfd24160SGreg Banks * lockd is brought up, so silently treat it the 358bfd24160SGreg Banks * same as SVC_POOL_GLOBAL. 359bfd24160SGreg Banks */ 36042a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) { 361bfd24160SGreg Banks switch (m->mode) { 362bfd24160SGreg Banks case SVC_POOL_PERCPU: 363bfd24160SGreg Banks pidx = m->to_pool[cpu]; 364bfd24160SGreg Banks break; 365bfd24160SGreg Banks case SVC_POOL_PERNODE: 366bfd24160SGreg Banks pidx = m->to_pool[cpu_to_node(cpu)]; 367bfd24160SGreg Banks break; 368bfd24160SGreg Banks } 36942a7fc4aSGreg Banks } 370bfd24160SGreg Banks return &serv->sv_pools[pidx % serv->sv_nrpools]; 371bfd24160SGreg Banks } 372bfd24160SGreg Banks 373bb2224dfSStanislav Kinsbursky int svc_rpcb_setup(struct svc_serv *serv, struct net *net) 374d9908560SStanislav Kinsbursky { 375d9908560SStanislav Kinsbursky int err; 376d9908560SStanislav Kinsbursky 377bee42f68SStanislav Kinsbursky err = rpcb_create_local(net); 378d9908560SStanislav Kinsbursky if (err) 379d9908560SStanislav Kinsbursky return err; 380d9908560SStanislav Kinsbursky 381d9908560SStanislav Kinsbursky /* Remove any stale portmap registrations */ 382bee42f68SStanislav Kinsbursky svc_unregister(serv, net); 383d9908560SStanislav Kinsbursky return 0; 384d9908560SStanislav Kinsbursky } 385bb2224dfSStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_setup); 386d9908560SStanislav Kinsbursky 3875ecebb7cSStanislav Kinsbursky void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) 388d9908560SStanislav Kinsbursky { 3895ecebb7cSStanislav Kinsbursky svc_unregister(serv, net); 3905ecebb7cSStanislav Kinsbursky rpcb_put_local(net); 391d9908560SStanislav Kinsbursky } 39216d05870SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); 393d9908560SStanislav Kinsbursky 394d9908560SStanislav Kinsbursky static int svc_uses_rpcbind(struct svc_serv *serv) 395d9908560SStanislav Kinsbursky { 396d9908560SStanislav Kinsbursky struct svc_program *progp; 397d9908560SStanislav Kinsbursky unsigned int i; 398d9908560SStanislav Kinsbursky 399d9908560SStanislav Kinsbursky for (progp = serv->sv_program; progp; progp = progp->pg_next) { 400d9908560SStanislav Kinsbursky for (i = 0; i < progp->pg_nvers; i++) { 401d9908560SStanislav Kinsbursky if (progp->pg_vers[i] == NULL) 402d9908560SStanislav Kinsbursky continue; 403d9908560SStanislav Kinsbursky if (progp->pg_vers[i]->vs_hidden == 0) 404d9908560SStanislav Kinsbursky return 1; 405d9908560SStanislav Kinsbursky } 406d9908560SStanislav Kinsbursky } 407d9908560SStanislav Kinsbursky 408d9908560SStanislav Kinsbursky return 0; 409d9908560SStanislav Kinsbursky } 410bfd24160SGreg Banks 4119793f7c8SStanislav Kinsbursky int svc_bind(struct svc_serv *serv, struct net *net) 4129793f7c8SStanislav Kinsbursky { 4139793f7c8SStanislav Kinsbursky if (!svc_uses_rpcbind(serv)) 4149793f7c8SStanislav Kinsbursky return 0; 4159793f7c8SStanislav Kinsbursky return svc_rpcb_setup(serv, net); 4169793f7c8SStanislav Kinsbursky } 4179793f7c8SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_bind); 4189793f7c8SStanislav Kinsbursky 419bfd24160SGreg Banks /* 4201da177e4SLinus Torvalds * Create an RPC service 4211da177e4SLinus Torvalds */ 422a7455442SGreg Banks static struct svc_serv * 423a7455442SGreg Banks __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, 4245ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net)) 4251da177e4SLinus Torvalds { 4261da177e4SLinus Torvalds struct svc_serv *serv; 427ea339d46SChuck Lever unsigned int vers; 4281da177e4SLinus Torvalds unsigned int xdrsize; 4293262c816SGreg Banks unsigned int i; 4301da177e4SLinus Torvalds 4310da974f4SPanagiotis Issaris if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) 4321da177e4SLinus Torvalds return NULL; 4339ba02638SAndreas Gruenbacher serv->sv_name = prog->pg_name; 4341da177e4SLinus Torvalds serv->sv_program = prog; 4351da177e4SLinus Torvalds serv->sv_nrthreads = 1; 4361da177e4SLinus Torvalds serv->sv_stats = prog->pg_stats; 437c6b0a9f8SNeilBrown if (bufsize > RPCSVC_MAXPAYLOAD) 438c6b0a9f8SNeilBrown bufsize = RPCSVC_MAXPAYLOAD; 439c6b0a9f8SNeilBrown serv->sv_max_payload = bufsize? bufsize : 4096; 440c6b0a9f8SNeilBrown serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); 441bc591ccfSNeilBrown serv->sv_shutdown = shutdown; 4421da177e4SLinus Torvalds xdrsize = 0; 4439ba02638SAndreas Gruenbacher while (prog) { 4449ba02638SAndreas Gruenbacher prog->pg_lovers = prog->pg_nvers-1; 4451da177e4SLinus Torvalds for (vers=0; vers<prog->pg_nvers ; vers++) 4461da177e4SLinus Torvalds if (prog->pg_vers[vers]) { 4471da177e4SLinus Torvalds prog->pg_hivers = vers; 4481da177e4SLinus Torvalds if (prog->pg_lovers > vers) 4491da177e4SLinus Torvalds prog->pg_lovers = vers; 4501da177e4SLinus Torvalds if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) 4511da177e4SLinus Torvalds xdrsize = prog->pg_vers[vers]->vs_xdrsize; 4521da177e4SLinus Torvalds } 4539ba02638SAndreas Gruenbacher prog = prog->pg_next; 4549ba02638SAndreas Gruenbacher } 4551da177e4SLinus Torvalds serv->sv_xdrsize = xdrsize; 4561da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_tempsocks); 4571da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_permsocks); 45836bdfc8bSGreg Banks init_timer(&serv->sv_temptimer); 4591da177e4SLinus Torvalds spin_lock_init(&serv->sv_lock); 4601da177e4SLinus Torvalds 461a7455442SGreg Banks serv->sv_nrpools = npools; 4623262c816SGreg Banks serv->sv_pools = 463cd861280SRobert P. J. Day kcalloc(serv->sv_nrpools, sizeof(struct svc_pool), 4643262c816SGreg Banks GFP_KERNEL); 4653262c816SGreg Banks if (!serv->sv_pools) { 4663262c816SGreg Banks kfree(serv); 4673262c816SGreg Banks return NULL; 4683262c816SGreg Banks } 4693262c816SGreg Banks 4703262c816SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 4713262c816SGreg Banks struct svc_pool *pool = &serv->sv_pools[i]; 4723262c816SGreg Banks 47346121cf7SChuck Lever dprintk("svc: initialising pool %u for %s\n", 4743262c816SGreg Banks i, serv->sv_name); 4753262c816SGreg Banks 4763262c816SGreg Banks pool->sp_id = i; 4773262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_threads); 4783262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_sockets); 479a7455442SGreg Banks INIT_LIST_HEAD(&pool->sp_all_threads); 4803262c816SGreg Banks spin_lock_init(&pool->sp_lock); 4813262c816SGreg Banks } 4823262c816SGreg Banks 4839793f7c8SStanislav Kinsbursky if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown)) 484e40f5e29SStanislav Kinsbursky serv->sv_shutdown = svc_rpcb_cleanup; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds return serv; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds 489a7455442SGreg Banks struct svc_serv * 490a7455442SGreg Banks svc_create(struct svc_program *prog, unsigned int bufsize, 4915ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net)) 492a7455442SGreg Banks { 49349a9072fSChuck Lever return __svc_create(prog, bufsize, /*npools*/1, shutdown); 494a7455442SGreg Banks } 49524c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create); 496a7455442SGreg Banks 497a7455442SGreg Banks struct svc_serv * 498a7455442SGreg Banks svc_create_pooled(struct svc_program *prog, unsigned int bufsize, 4995ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net), 500a75c5d01SJeff Layton svc_thread_fn func, struct module *mod) 501a7455442SGreg Banks { 502a7455442SGreg Banks struct svc_serv *serv; 50342a7fc4aSGreg Banks unsigned int npools = svc_pool_map_get(); 504a7455442SGreg Banks 50549a9072fSChuck Lever serv = __svc_create(prog, bufsize, npools, shutdown); 506a7455442SGreg Banks 507a7455442SGreg Banks if (serv != NULL) { 508a7455442SGreg Banks serv->sv_function = func; 509a7455442SGreg Banks serv->sv_module = mod; 510a7455442SGreg Banks } 511a7455442SGreg Banks 512a7455442SGreg Banks return serv; 513a7455442SGreg Banks } 51424c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create_pooled); 515a7455442SGreg Banks 516074d0f67SStanislav Kinsbursky void svc_shutdown_net(struct svc_serv *serv, struct net *net) 517074d0f67SStanislav Kinsbursky { 518074d0f67SStanislav Kinsbursky svc_close_net(serv, net); 519074d0f67SStanislav Kinsbursky 520074d0f67SStanislav Kinsbursky if (serv->sv_shutdown) 521074d0f67SStanislav Kinsbursky serv->sv_shutdown(serv, net); 522074d0f67SStanislav Kinsbursky } 523074d0f67SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_shutdown_net); 524074d0f67SStanislav Kinsbursky 5251da177e4SLinus Torvalds /* 526bedbdd8bSNeil Brown * Destroy an RPC service. Should be called with appropriate locking to 527bedbdd8bSNeil Brown * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. 5281da177e4SLinus Torvalds */ 5291da177e4SLinus Torvalds void 5301da177e4SLinus Torvalds svc_destroy(struct svc_serv *serv) 5311da177e4SLinus Torvalds { 53246121cf7SChuck Lever dprintk("svc: svc_destroy(%s, %d)\n", 5331da177e4SLinus Torvalds serv->sv_program->pg_name, 5341da177e4SLinus Torvalds serv->sv_nrthreads); 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds if (serv->sv_nrthreads) { 5371da177e4SLinus Torvalds if (--(serv->sv_nrthreads) != 0) { 5381da177e4SLinus Torvalds svc_sock_update_bufs(serv); 5391da177e4SLinus Torvalds return; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds } else 5421da177e4SLinus Torvalds printk("svc_destroy: no threads for serv=%p!\n", serv); 5431da177e4SLinus Torvalds 54436bdfc8bSGreg Banks del_timer_sync(&serv->sv_temptimer); 545074d0f67SStanislav Kinsbursky 5467b147f1fSStanislav Kinsbursky /* 5477b147f1fSStanislav Kinsbursky * The last user is gone and thus all sockets have to be destroyed to 5487b147f1fSStanislav Kinsbursky * the point. Check this. 5497b147f1fSStanislav Kinsbursky */ 5507b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_permsocks)); 5517b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_tempsocks)); 552cda1fd4aSNeilBrown 5531da177e4SLinus Torvalds cache_clean_deferred(serv); 5541da177e4SLinus Torvalds 55542a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) 55642a7fc4aSGreg Banks svc_pool_map_put(); 55742a7fc4aSGreg Banks 5583262c816SGreg Banks kfree(serv->sv_pools); 5591da177e4SLinus Torvalds kfree(serv); 5601da177e4SLinus Torvalds } 56124c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_destroy); 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds /* 5641da177e4SLinus Torvalds * Allocate an RPC server's buffer space. 5651da177e4SLinus Torvalds * We allocate pages and place them in rq_argpages. 5661da177e4SLinus Torvalds */ 5671da177e4SLinus Torvalds static int 56811fd165cSEric Dumazet svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node) 5691da177e4SLinus Torvalds { 5700dc220f0SChuck Lever unsigned int pages, arghi; 5711da177e4SLinus Torvalds 572ba17686fSAndy Adamson /* bc_xprt uses fore channel allocated buffers */ 573ba17686fSAndy Adamson if (svc_is_backchannel(rqstp)) 574ba17686fSAndy Adamson return 1; 575ba17686fSAndy Adamson 576c6b0a9f8SNeilBrown pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. 577c6b0a9f8SNeilBrown * We assume one is at most one page 578c6b0a9f8SNeilBrown */ 5791da177e4SLinus Torvalds arghi = 0; 580b25cd058SWeston Andros Adamson WARN_ON_ONCE(pages > RPCSVC_MAXPAGES); 581b25cd058SWeston Andros Adamson if (pages > RPCSVC_MAXPAGES) 582b25cd058SWeston Andros Adamson pages = RPCSVC_MAXPAGES; 5831da177e4SLinus Torvalds while (pages) { 58411fd165cSEric Dumazet struct page *p = alloc_pages_node(node, GFP_KERNEL, 0); 5851da177e4SLinus Torvalds if (!p) 5861da177e4SLinus Torvalds break; 58744524359SNeilBrown rqstp->rq_pages[arghi++] = p; 5881da177e4SLinus Torvalds pages--; 5891da177e4SLinus Torvalds } 5900dc220f0SChuck Lever return pages == 0; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* 5941da177e4SLinus Torvalds * Release an RPC server buffer 5951da177e4SLinus Torvalds */ 5961da177e4SLinus Torvalds static void 5971da177e4SLinus Torvalds svc_release_buffer(struct svc_rqst *rqstp) 5981da177e4SLinus Torvalds { 59950c8bb13SChuck Lever unsigned int i; 60050c8bb13SChuck Lever 60144524359SNeilBrown for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) 60244524359SNeilBrown if (rqstp->rq_pages[i]) 60344524359SNeilBrown put_page(rqstp->rq_pages[i]); 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 6060113ab34SJeff Layton struct svc_rqst * 60711fd165cSEric Dumazet svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) 6080113ab34SJeff Layton { 6090113ab34SJeff Layton struct svc_rqst *rqstp; 6100113ab34SJeff Layton 61111fd165cSEric Dumazet rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node); 6120113ab34SJeff Layton if (!rqstp) 6130113ab34SJeff Layton goto out_enomem; 6140113ab34SJeff Layton 6150113ab34SJeff Layton init_waitqueue_head(&rqstp->rq_wait); 6160113ab34SJeff Layton 6170113ab34SJeff Layton serv->sv_nrthreads++; 6180113ab34SJeff Layton spin_lock_bh(&pool->sp_lock); 6190113ab34SJeff Layton pool->sp_nrthreads++; 6200113ab34SJeff Layton list_add(&rqstp->rq_all, &pool->sp_all_threads); 6210113ab34SJeff Layton spin_unlock_bh(&pool->sp_lock); 6220113ab34SJeff Layton rqstp->rq_server = serv; 6230113ab34SJeff Layton rqstp->rq_pool = pool; 6240113ab34SJeff Layton 62511fd165cSEric Dumazet rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6260113ab34SJeff Layton if (!rqstp->rq_argp) 6270113ab34SJeff Layton goto out_thread; 6280113ab34SJeff Layton 62911fd165cSEric Dumazet rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6300113ab34SJeff Layton if (!rqstp->rq_resp) 6310113ab34SJeff Layton goto out_thread; 6320113ab34SJeff Layton 63311fd165cSEric Dumazet if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node)) 6340113ab34SJeff Layton goto out_thread; 6350113ab34SJeff Layton 6360113ab34SJeff Layton return rqstp; 6370113ab34SJeff Layton out_thread: 6380113ab34SJeff Layton svc_exit_thread(rqstp); 6390113ab34SJeff Layton out_enomem: 6400113ab34SJeff Layton return ERR_PTR(-ENOMEM); 6410113ab34SJeff Layton } 64224c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_prepare_thread); 6430113ab34SJeff Layton 6441da177e4SLinus Torvalds /* 645a7455442SGreg Banks * Choose a pool in which to create a new thread, for svc_set_num_threads 646a7455442SGreg Banks */ 647a7455442SGreg Banks static inline struct svc_pool * 648a7455442SGreg Banks choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 649a7455442SGreg Banks { 650a7455442SGreg Banks if (pool != NULL) 651a7455442SGreg Banks return pool; 652a7455442SGreg Banks 653a7455442SGreg Banks return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; 654a7455442SGreg Banks } 655a7455442SGreg Banks 656a7455442SGreg Banks /* 657a7455442SGreg Banks * Choose a thread to kill, for svc_set_num_threads 658a7455442SGreg Banks */ 659a7455442SGreg Banks static inline struct task_struct * 660a7455442SGreg Banks choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 661a7455442SGreg Banks { 662a7455442SGreg Banks unsigned int i; 663a7455442SGreg Banks struct task_struct *task = NULL; 664a7455442SGreg Banks 665a7455442SGreg Banks if (pool != NULL) { 666a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 667a7455442SGreg Banks } else { 668a7455442SGreg Banks /* choose a pool in round-robin fashion */ 669a7455442SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 670a7455442SGreg Banks pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; 671a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 672a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) 673a7455442SGreg Banks goto found_pool; 674a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 675a7455442SGreg Banks } 676a7455442SGreg Banks return NULL; 677a7455442SGreg Banks } 678a7455442SGreg Banks 679a7455442SGreg Banks found_pool: 680a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) { 681a7455442SGreg Banks struct svc_rqst *rqstp; 682a7455442SGreg Banks 683a7455442SGreg Banks /* 684a7455442SGreg Banks * Remove from the pool->sp_all_threads list 685a7455442SGreg Banks * so we don't try to kill it again. 686a7455442SGreg Banks */ 687a7455442SGreg Banks rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); 688a7455442SGreg Banks list_del_init(&rqstp->rq_all); 689a7455442SGreg Banks task = rqstp->rq_task; 690a7455442SGreg Banks } 691a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 692a7455442SGreg Banks 693a7455442SGreg Banks return task; 694a7455442SGreg Banks } 695a7455442SGreg Banks 696a7455442SGreg Banks /* 697a7455442SGreg Banks * Create or destroy enough new threads to make the number 698a7455442SGreg Banks * of threads the given number. If `pool' is non-NULL, applies 699a7455442SGreg Banks * only to threads in that pool, otherwise round-robins between 70094cf3179SJ. Bruce Fields * all pools. Caller must ensure that mutual exclusion between this and 70194cf3179SJ. Bruce Fields * server startup or shutdown. 702a7455442SGreg Banks * 703a7455442SGreg Banks * Destroying threads relies on the service threads filling in 704a7455442SGreg Banks * rqstp->rq_task, which only the nfs ones do. Assumes the serv 705a7455442SGreg Banks * has been created using svc_create_pooled(). 706a7455442SGreg Banks * 707a7455442SGreg Banks * Based on code that used to be in nfsd_svc() but tweaked 708a7455442SGreg Banks * to be pool-aware. 709a7455442SGreg Banks */ 710a7455442SGreg Banks int 711a7455442SGreg Banks svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 712a7455442SGreg Banks { 7139867d76cSJeff Layton struct svc_rqst *rqstp; 7149867d76cSJeff Layton struct task_struct *task; 7159867d76cSJeff Layton struct svc_pool *chosen_pool; 716a7455442SGreg Banks int error = 0; 717a7455442SGreg Banks unsigned int state = serv->sv_nrthreads-1; 71811fd165cSEric Dumazet int node; 719a7455442SGreg Banks 720a7455442SGreg Banks if (pool == NULL) { 721a7455442SGreg Banks /* The -1 assumes caller has done a svc_get() */ 722a7455442SGreg Banks nrservs -= (serv->sv_nrthreads-1); 723a7455442SGreg Banks } else { 724a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 725a7455442SGreg Banks nrservs -= pool->sp_nrthreads; 726a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 727a7455442SGreg Banks } 728a7455442SGreg Banks 729a7455442SGreg Banks /* create new threads */ 730a7455442SGreg Banks while (nrservs > 0) { 731a7455442SGreg Banks nrservs--; 7329867d76cSJeff Layton chosen_pool = choose_pool(serv, pool, &state); 7339867d76cSJeff Layton 73411fd165cSEric Dumazet node = svc_pool_map_get_node(chosen_pool->sp_id); 73511fd165cSEric Dumazet rqstp = svc_prepare_thread(serv, chosen_pool, node); 7369867d76cSJeff Layton if (IS_ERR(rqstp)) { 7379867d76cSJeff Layton error = PTR_ERR(rqstp); 738a7455442SGreg Banks break; 739a7455442SGreg Banks } 7409867d76cSJeff Layton 7419867d76cSJeff Layton __module_get(serv->sv_module); 74211fd165cSEric Dumazet task = kthread_create_on_node(serv->sv_function, rqstp, 743f170168bSKees Cook node, "%s", serv->sv_name); 7449867d76cSJeff Layton if (IS_ERR(task)) { 7459867d76cSJeff Layton error = PTR_ERR(task); 7469867d76cSJeff Layton module_put(serv->sv_module); 7479867d76cSJeff Layton svc_exit_thread(rqstp); 7489867d76cSJeff Layton break; 7499867d76cSJeff Layton } 7509867d76cSJeff Layton 7519867d76cSJeff Layton rqstp->rq_task = task; 7529867d76cSJeff Layton if (serv->sv_nrpools > 1) 7539867d76cSJeff Layton svc_pool_map_set_cpumask(task, chosen_pool->sp_id); 7549867d76cSJeff Layton 7559867d76cSJeff Layton svc_sock_update_bufs(serv); 7569867d76cSJeff Layton wake_up_process(task); 757a7455442SGreg Banks } 758a7455442SGreg Banks /* destroy old threads */ 759a7455442SGreg Banks while (nrservs < 0 && 7609867d76cSJeff Layton (task = choose_victim(serv, pool, &state)) != NULL) { 761a75c5d01SJeff Layton send_sig(SIGINT, task, 1); 762a7455442SGreg Banks nrservs++; 763a7455442SGreg Banks } 764a7455442SGreg Banks 765a7455442SGreg Banks return error; 766a7455442SGreg Banks } 76724c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_set_num_threads); 768a7455442SGreg Banks 769a7455442SGreg Banks /* 770bedbdd8bSNeil Brown * Called from a server thread as it's exiting. Caller must hold the BKL or 771bedbdd8bSNeil Brown * the "service mutex", whichever is appropriate for the service. 7721da177e4SLinus Torvalds */ 7731da177e4SLinus Torvalds void 7741da177e4SLinus Torvalds svc_exit_thread(struct svc_rqst *rqstp) 7751da177e4SLinus Torvalds { 7761da177e4SLinus Torvalds struct svc_serv *serv = rqstp->rq_server; 7773262c816SGreg Banks struct svc_pool *pool = rqstp->rq_pool; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds svc_release_buffer(rqstp); 7801da177e4SLinus Torvalds kfree(rqstp->rq_resp); 7811da177e4SLinus Torvalds kfree(rqstp->rq_argp); 7821da177e4SLinus Torvalds kfree(rqstp->rq_auth_data); 7833262c816SGreg Banks 7843262c816SGreg Banks spin_lock_bh(&pool->sp_lock); 7853262c816SGreg Banks pool->sp_nrthreads--; 786a7455442SGreg Banks list_del(&rqstp->rq_all); 7873262c816SGreg Banks spin_unlock_bh(&pool->sp_lock); 7883262c816SGreg Banks 7891da177e4SLinus Torvalds kfree(rqstp); 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds /* Release the server */ 7921da177e4SLinus Torvalds if (serv) 7931da177e4SLinus Torvalds svc_destroy(serv); 7941da177e4SLinus Torvalds } 79524c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_exit_thread); 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds /* 7982c7eb0b2SChuck Lever * Register an "inet" protocol family netid with the local 7992c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 800a26cfad6SChuck Lever * 8012c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8022c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 803a26cfad6SChuck Lever * 8042c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8052c7eb0b2SChuck Lever * if any error occurs. 8061da177e4SLinus Torvalds */ 8075247fab5SStanislav Kinsbursky static int __svc_rpcb_register4(struct net *net, const u32 program, 8085247fab5SStanislav Kinsbursky const u32 version, 809a26cfad6SChuck Lever const unsigned short protocol, 810a26cfad6SChuck Lever const unsigned short port) 811a26cfad6SChuck Lever { 812cadc0fa5SChuck Lever const struct sockaddr_in sin = { 813a26cfad6SChuck Lever .sin_family = AF_INET, 814a26cfad6SChuck Lever .sin_addr.s_addr = htonl(INADDR_ANY), 815a26cfad6SChuck Lever .sin_port = htons(port), 816a26cfad6SChuck Lever }; 817cadc0fa5SChuck Lever const char *netid; 818cadc0fa5SChuck Lever int error; 8192c7eb0b2SChuck Lever 8202c7eb0b2SChuck Lever switch (protocol) { 8212c7eb0b2SChuck Lever case IPPROTO_UDP: 8222c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP; 8232c7eb0b2SChuck Lever break; 8242c7eb0b2SChuck Lever case IPPROTO_TCP: 8252c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP; 8262c7eb0b2SChuck Lever break; 8272c7eb0b2SChuck Lever default: 828ba5c35e0SChuck Lever return -ENOPROTOOPT; 8292c7eb0b2SChuck Lever } 8302c7eb0b2SChuck Lever 8315247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 832cadc0fa5SChuck Lever (const struct sockaddr *)&sin, netid); 833cadc0fa5SChuck Lever 834cadc0fa5SChuck Lever /* 835cadc0fa5SChuck Lever * User space didn't support rpcbind v4, so retry this 836cadc0fa5SChuck Lever * registration request with the legacy rpcbind v2 protocol. 837cadc0fa5SChuck Lever */ 838cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 8395247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, protocol, port); 840cadc0fa5SChuck Lever 841cadc0fa5SChuck Lever return error; 8422c7eb0b2SChuck Lever } 8432c7eb0b2SChuck Lever 844dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 8452c7eb0b2SChuck Lever /* 8462c7eb0b2SChuck Lever * Register an "inet6" protocol family netid with the local 8472c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 8482c7eb0b2SChuck Lever * 8492c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8502c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 8512c7eb0b2SChuck Lever * 8522c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8532c7eb0b2SChuck Lever * if any error occurs. 8542c7eb0b2SChuck Lever */ 8555247fab5SStanislav Kinsbursky static int __svc_rpcb_register6(struct net *net, const u32 program, 8565247fab5SStanislav Kinsbursky const u32 version, 8572c7eb0b2SChuck Lever const unsigned short protocol, 8582c7eb0b2SChuck Lever const unsigned short port) 8592c7eb0b2SChuck Lever { 860cadc0fa5SChuck Lever const struct sockaddr_in6 sin6 = { 861a26cfad6SChuck Lever .sin6_family = AF_INET6, 862a26cfad6SChuck Lever .sin6_addr = IN6ADDR_ANY_INIT, 863a26cfad6SChuck Lever .sin6_port = htons(port), 864a26cfad6SChuck Lever }; 865cadc0fa5SChuck Lever const char *netid; 866cadc0fa5SChuck Lever int error; 867a26cfad6SChuck Lever 8682c7eb0b2SChuck Lever switch (protocol) { 8692c7eb0b2SChuck Lever case IPPROTO_UDP: 8702c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP6; 8712c7eb0b2SChuck Lever break; 8722c7eb0b2SChuck Lever case IPPROTO_TCP: 8732c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP6; 8742c7eb0b2SChuck Lever break; 8752c7eb0b2SChuck Lever default: 876ba5c35e0SChuck Lever return -ENOPROTOOPT; 8772c7eb0b2SChuck Lever } 8782c7eb0b2SChuck Lever 8795247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 880cadc0fa5SChuck Lever (const struct sockaddr *)&sin6, netid); 881cadc0fa5SChuck Lever 882cadc0fa5SChuck Lever /* 883cadc0fa5SChuck Lever * User space didn't support rpcbind version 4, so we won't 884cadc0fa5SChuck Lever * use a PF_INET6 listener. 885cadc0fa5SChuck Lever */ 886cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 887cadc0fa5SChuck Lever error = -EAFNOSUPPORT; 888cadc0fa5SChuck Lever 889cadc0fa5SChuck Lever return error; 8902c7eb0b2SChuck Lever } 891dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 8922c7eb0b2SChuck Lever 8932c7eb0b2SChuck Lever /* 8942c7eb0b2SChuck Lever * Register a kernel RPC service via rpcbind version 4. 8952c7eb0b2SChuck Lever * 8962c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8972c7eb0b2SChuck Lever * if any error occurs. 8982c7eb0b2SChuck Lever */ 8995247fab5SStanislav Kinsbursky static int __svc_register(struct net *net, const char *progname, 900363f724cSChuck Lever const u32 program, const u32 version, 9014b62e58cSChuck Lever const int family, 9022c7eb0b2SChuck Lever const unsigned short protocol, 9032c7eb0b2SChuck Lever const unsigned short port) 9042c7eb0b2SChuck Lever { 905363f724cSChuck Lever int error = -EAFNOSUPPORT; 9062c7eb0b2SChuck Lever 907a26cfad6SChuck Lever switch (family) { 9084b62e58cSChuck Lever case PF_INET: 9095247fab5SStanislav Kinsbursky error = __svc_rpcb_register4(net, program, version, 9102c7eb0b2SChuck Lever protocol, port); 911cadc0fa5SChuck Lever break; 912dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 9134b62e58cSChuck Lever case PF_INET6: 9145247fab5SStanislav Kinsbursky error = __svc_rpcb_register6(net, program, version, 9152c7eb0b2SChuck Lever protocol, port); 916dfd56b8bSEric Dumazet #endif 9172c7eb0b2SChuck Lever } 9182c7eb0b2SChuck Lever 919a26cfad6SChuck Lever return error; 920a26cfad6SChuck Lever } 921a26cfad6SChuck Lever 922a26cfad6SChuck Lever /** 923a26cfad6SChuck Lever * svc_register - register an RPC service with the local portmapper 924a26cfad6SChuck Lever * @serv: svc_serv struct for the service to register 9255247fab5SStanislav Kinsbursky * @net: net namespace for the service to register 9264b62e58cSChuck Lever * @family: protocol family of service's listener socket 927a26cfad6SChuck Lever * @proto: transport protocol number to advertise 928a26cfad6SChuck Lever * @port: port to advertise 929a26cfad6SChuck Lever * 9304b62e58cSChuck Lever * Service is registered for any address in the passed-in protocol family 931a26cfad6SChuck Lever */ 9325247fab5SStanislav Kinsbursky int svc_register(const struct svc_serv *serv, struct net *net, 9335247fab5SStanislav Kinsbursky const int family, const unsigned short proto, 9345247fab5SStanislav Kinsbursky const unsigned short port) 9351da177e4SLinus Torvalds { 9361da177e4SLinus Torvalds struct svc_program *progp; 937*7e55b59bSKinglong Mee struct svc_version *vers; 938ea339d46SChuck Lever unsigned int i; 93914aeb211SChuck Lever int error = 0; 9401da177e4SLinus Torvalds 9410af39507SWeston Andros Adamson WARN_ON_ONCE(proto == 0 && port == 0); 9420af39507SWeston Andros Adamson if (proto == 0 && port == 0) 9430af39507SWeston Andros Adamson return -EINVAL; 9441da177e4SLinus Torvalds 945bc5fea42SOlaf Kirch for (progp = serv->sv_program; progp; progp = progp->pg_next) { 9461da177e4SLinus Torvalds for (i = 0; i < progp->pg_nvers; i++) { 947*7e55b59bSKinglong Mee vers = progp->pg_vers[i]; 948*7e55b59bSKinglong Mee if (vers == NULL) 9491da177e4SLinus Torvalds continue; 950bc5fea42SOlaf Kirch 9512c7eb0b2SChuck Lever dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", 952bc5fea42SOlaf Kirch progp->pg_name, 9532c7eb0b2SChuck Lever i, 954bc5fea42SOlaf Kirch proto == IPPROTO_UDP? "udp" : "tcp", 955bc5fea42SOlaf Kirch port, 9564b62e58cSChuck Lever family, 957*7e55b59bSKinglong Mee vers->vs_hidden ? 958bc5fea42SOlaf Kirch " (but not telling portmap)" : ""); 959bc5fea42SOlaf Kirch 960*7e55b59bSKinglong Mee if (vers->vs_hidden) 961bc5fea42SOlaf Kirch continue; 962bc5fea42SOlaf Kirch 9635247fab5SStanislav Kinsbursky error = __svc_register(net, progp->pg_name, progp->pg_prog, 964363f724cSChuck Lever i, family, proto, port); 965*7e55b59bSKinglong Mee 966*7e55b59bSKinglong Mee if (vers->vs_rpcb_optnl) { 967*7e55b59bSKinglong Mee error = 0; 968*7e55b59bSKinglong Mee continue; 969*7e55b59bSKinglong Mee } 970*7e55b59bSKinglong Mee 971*7e55b59bSKinglong Mee if (error < 0) { 972*7e55b59bSKinglong Mee printk(KERN_WARNING "svc: failed to register " 973*7e55b59bSKinglong Mee "%sv%u RPC service (errno %d).\n", 974*7e55b59bSKinglong Mee progp->pg_name, i, -error); 9751da177e4SLinus Torvalds break; 9761da177e4SLinus Torvalds } 977bc5fea42SOlaf Kirch } 978*7e55b59bSKinglong Mee } 9791da177e4SLinus Torvalds 9807252d575SChuck Lever return error; 9817252d575SChuck Lever } 9827252d575SChuck Lever 983d5a8620fSChuck Lever /* 984d5a8620fSChuck Lever * If user space is running rpcbind, it should take the v4 UNSET 985d5a8620fSChuck Lever * and clear everything for this [program, version]. If user space 986d5a8620fSChuck Lever * is running portmap, it will reject the v4 UNSET, but won't have 987d5a8620fSChuck Lever * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient 988d5a8620fSChuck Lever * in this case to clear all existing entries for [program, version]. 989d5a8620fSChuck Lever */ 9905247fab5SStanislav Kinsbursky static void __svc_unregister(struct net *net, const u32 program, const u32 version, 991f6fb3f6fSChuck Lever const char *progname) 992f6fb3f6fSChuck Lever { 993f6fb3f6fSChuck Lever int error; 994f6fb3f6fSChuck Lever 9955247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, NULL, ""); 996d5a8620fSChuck Lever 997d5a8620fSChuck Lever /* 998d5a8620fSChuck Lever * User space didn't support rpcbind v4, so retry this 999d5a8620fSChuck Lever * request with the legacy rpcbind v2 protocol. 1000d5a8620fSChuck Lever */ 1001d5a8620fSChuck Lever if (error == -EPROTONOSUPPORT) 10025247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, 0, 0); 1003d5a8620fSChuck Lever 1004f6fb3f6fSChuck Lever dprintk("svc: %s(%sv%u), error %d\n", 1005f6fb3f6fSChuck Lever __func__, progname, version, error); 1006f6fb3f6fSChuck Lever } 1007f6fb3f6fSChuck Lever 10087252d575SChuck Lever /* 1009f6fb3f6fSChuck Lever * All netids, bind addresses and ports registered for [program, version] 1010f6fb3f6fSChuck Lever * are removed from the local rpcbind database (if the service is not 1011f6fb3f6fSChuck Lever * hidden) to make way for a new instance of the service. 10127252d575SChuck Lever * 1013f6fb3f6fSChuck Lever * The result of unregistration is reported via dprintk for those who want 1014f6fb3f6fSChuck Lever * verification of the result, but is otherwise not important. 10157252d575SChuck Lever */ 10165247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net) 10177252d575SChuck Lever { 10187252d575SChuck Lever struct svc_program *progp; 10197252d575SChuck Lever unsigned long flags; 10207252d575SChuck Lever unsigned int i; 10217252d575SChuck Lever 10227252d575SChuck Lever clear_thread_flag(TIF_SIGPENDING); 10237252d575SChuck Lever 10247252d575SChuck Lever for (progp = serv->sv_program; progp; progp = progp->pg_next) { 10257252d575SChuck Lever for (i = 0; i < progp->pg_nvers; i++) { 10267252d575SChuck Lever if (progp->pg_vers[i] == NULL) 10277252d575SChuck Lever continue; 10287252d575SChuck Lever if (progp->pg_vers[i]->vs_hidden) 10297252d575SChuck Lever continue; 10307252d575SChuck Lever 10317402ab19SChuck Lever dprintk("svc: attempting to unregister %sv%u\n", 10327402ab19SChuck Lever progp->pg_name, i); 10335247fab5SStanislav Kinsbursky __svc_unregister(net, progp->pg_prog, i, progp->pg_name); 10347252d575SChuck Lever } 10357252d575SChuck Lever } 10367252d575SChuck Lever 10371da177e4SLinus Torvalds spin_lock_irqsave(¤t->sighand->siglock, flags); 10381da177e4SLinus Torvalds recalc_sigpending(); 10391da177e4SLinus Torvalds spin_unlock_irqrestore(¤t->sighand->siglock, flags); 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds /* 10437032a3ddSJ. Bruce Fields * dprintk the given error with the address of the client that caused it. 1044354ecbb9SDr. David Alan Gilbert */ 1045624ab464SJ. Bruce Fields #ifdef RPC_DEBUG 1046b9075fa9SJoe Perches static __printf(2, 3) 1047e87cc472SJoe Perches void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) 1048354ecbb9SDr. David Alan Gilbert { 1049e87cc472SJoe Perches struct va_format vaf; 1050354ecbb9SDr. David Alan Gilbert va_list args; 1051354ecbb9SDr. David Alan Gilbert char buf[RPC_MAX_ADDRBUFLEN]; 1052354ecbb9SDr. David Alan Gilbert 1053354ecbb9SDr. David Alan Gilbert va_start(args, fmt); 1054354ecbb9SDr. David Alan Gilbert 1055e87cc472SJoe Perches vaf.fmt = fmt; 1056e87cc472SJoe Perches vaf.va = &args; 1057e87cc472SJoe Perches 10587032a3ddSJ. Bruce Fields dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); 1059e87cc472SJoe Perches 1060e87cc472SJoe Perches va_end(args); 1061354ecbb9SDr. David Alan Gilbert } 1062624ab464SJ. Bruce Fields #else 1063624ab464SJ. Bruce Fields static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} 1064624ab464SJ. Bruce Fields #endif 1065354ecbb9SDr. David Alan Gilbert 1066354ecbb9SDr. David Alan Gilbert /* 10671cad7ea6SRicardo Labiaga * Common routine for processing the RPC request. 10681da177e4SLinus Torvalds */ 10691cad7ea6SRicardo Labiaga static int 10701cad7ea6SRicardo Labiaga svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) 10711da177e4SLinus Torvalds { 10721da177e4SLinus Torvalds struct svc_program *progp; 10731da177e4SLinus Torvalds struct svc_version *versp = NULL; /* compiler food */ 10741da177e4SLinus Torvalds struct svc_procedure *procp = NULL; 10756fb2b47fSNeilBrown struct svc_serv *serv = rqstp->rq_server; 10761da177e4SLinus Torvalds kxdrproc_t xdr; 1077d8ed029dSAlexey Dobriyan __be32 *statp; 10781cad7ea6SRicardo Labiaga u32 prog, vers, proc; 1079d8ed029dSAlexey Dobriyan __be32 auth_stat, rpc_stat; 10801da177e4SLinus Torvalds int auth_res; 10818f8e05c5SJ.Bruce Fields __be32 *reply_statp; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds rpc_stat = rpc_success; 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds if (argv->iov_len < 6*4) 10861da177e4SLinus Torvalds goto err_short_len; 10871da177e4SLinus Torvalds 10885c04c46aSJ. Bruce Fields /* Will be turned off only in gss privacy case: */ 1089cf8208d0SJens Axboe rqstp->rq_splice_ok = 1; 10902f425878SAndy Adamson /* Will be turned off only when NFSv4 Sessions are used */ 10912f425878SAndy Adamson rqstp->rq_usedeferral = 1; 10929e701c61SJ. Bruce Fields rqstp->rq_dropme = false; 1093e831fe65STom Tucker 1094e831fe65STom Tucker /* Setup reply header */ 1095e831fe65STom Tucker rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds svc_putu32(resv, rqstp->rq_xid); 10981da177e4SLinus Torvalds 109976994313SAlexey Dobriyan vers = svc_getnl(argv); 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds /* First words of reply: */ 110276994313SAlexey Dobriyan svc_putnl(resv, 1); /* REPLY */ 11031da177e4SLinus Torvalds 11041da177e4SLinus Torvalds if (vers != 2) /* RPC version number */ 11051da177e4SLinus Torvalds goto err_bad_rpc; 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds /* Save position in case we later decide to reject: */ 11088f8e05c5SJ.Bruce Fields reply_statp = resv->iov_base + resv->iov_len; 11091da177e4SLinus Torvalds 111076994313SAlexey Dobriyan svc_putnl(resv, 0); /* ACCEPT */ 11111da177e4SLinus Torvalds 111276994313SAlexey Dobriyan rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ 111376994313SAlexey Dobriyan rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ 111476994313SAlexey Dobriyan rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ 11151da177e4SLinus Torvalds 111680d188a6SNeilBrown for (progp = serv->sv_program; progp; progp = progp->pg_next) 111780d188a6SNeilBrown if (prog == progp->pg_prog) 111880d188a6SNeilBrown break; 111980d188a6SNeilBrown 11201da177e4SLinus Torvalds /* 11211da177e4SLinus Torvalds * Decode auth data, and add verifier to reply buffer. 11221da177e4SLinus Torvalds * We do this before anything else in order to get a decent 11231da177e4SLinus Torvalds * auth verifier. 11241da177e4SLinus Torvalds */ 11251da177e4SLinus Torvalds auth_res = svc_authenticate(rqstp, &auth_stat); 11261da177e4SLinus Torvalds /* Also give the program a chance to reject this call: */ 112780d188a6SNeilBrown if (auth_res == SVC_OK && progp) { 11281da177e4SLinus Torvalds auth_stat = rpc_autherr_badcred; 11291da177e4SLinus Torvalds auth_res = progp->pg_authenticate(rqstp); 11301da177e4SLinus Torvalds } 11311da177e4SLinus Torvalds switch (auth_res) { 11321da177e4SLinus Torvalds case SVC_OK: 11331da177e4SLinus Torvalds break; 11341da177e4SLinus Torvalds case SVC_GARBAGE: 1135dd35210eSHarshula Jayasuriya goto err_garbage; 11361da177e4SLinus Torvalds case SVC_SYSERR: 11371da177e4SLinus Torvalds rpc_stat = rpc_system_err; 11381da177e4SLinus Torvalds goto err_bad; 11391da177e4SLinus Torvalds case SVC_DENIED: 11401da177e4SLinus Torvalds goto err_bad_auth; 11411ebede86SNeilBrown case SVC_CLOSE: 11421ebede86SNeilBrown if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) 11431ebede86SNeilBrown svc_close_xprt(rqstp->rq_xprt); 11441da177e4SLinus Torvalds case SVC_DROP: 11451da177e4SLinus Torvalds goto dropit; 11461da177e4SLinus Torvalds case SVC_COMPLETE: 11471da177e4SLinus Torvalds goto sendit; 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds 11509ba02638SAndreas Gruenbacher if (progp == NULL) 11511da177e4SLinus Torvalds goto err_bad_prog; 11521da177e4SLinus Torvalds 11531da177e4SLinus Torvalds if (vers >= progp->pg_nvers || 11541da177e4SLinus Torvalds !(versp = progp->pg_vers[vers])) 11551da177e4SLinus Torvalds goto err_bad_vers; 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds procp = versp->vs_proc + proc; 11581da177e4SLinus Torvalds if (proc >= versp->vs_nproc || !procp->pc_func) 11591da177e4SLinus Torvalds goto err_bad_proc; 11601da177e4SLinus Torvalds rqstp->rq_procinfo = procp; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds /* Syntactic check complete */ 11631da177e4SLinus Torvalds serv->sv_stats->rpccnt++; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds /* Build the reply header. */ 11661da177e4SLinus Torvalds statp = resv->iov_base +resv->iov_len; 116776994313SAlexey Dobriyan svc_putnl(resv, RPC_SUCCESS); 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds /* Bump per-procedure stats counter */ 11701da177e4SLinus Torvalds procp->pc_count++; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds /* Initialize storage for argp and resp */ 11731da177e4SLinus Torvalds memset(rqstp->rq_argp, 0, procp->pc_argsize); 11741da177e4SLinus Torvalds memset(rqstp->rq_resp, 0, procp->pc_ressize); 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds /* un-reserve some of the out-queue now that we have a 11771da177e4SLinus Torvalds * better idea of reply size 11781da177e4SLinus Torvalds */ 11791da177e4SLinus Torvalds if (procp->pc_xdrressize) 1180cd123012SJeff Layton svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds /* Call the function that processes the request. */ 11831da177e4SLinus Torvalds if (!versp->vs_dispatch) { 11841da177e4SLinus Torvalds /* Decode arguments */ 11851da177e4SLinus Torvalds xdr = procp->pc_decode; 11861da177e4SLinus Torvalds if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) 11871da177e4SLinus Torvalds goto err_garbage; 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds /* Encode reply */ 11929e701c61SJ. Bruce Fields if (rqstp->rq_dropme) { 1193d343fce1SNeilBrown if (procp->pc_release) 1194d343fce1SNeilBrown procp->pc_release(rqstp, NULL, rqstp->rq_resp); 1195d343fce1SNeilBrown goto dropit; 1196d343fce1SNeilBrown } 1197f64f9e71SJoe Perches if (*statp == rpc_success && 1198f64f9e71SJoe Perches (xdr = procp->pc_encode) && 1199f64f9e71SJoe Perches !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { 12001da177e4SLinus Torvalds dprintk("svc: failed to encode reply\n"); 12011da177e4SLinus Torvalds /* serv->sv_stats->rpcsystemerr++; */ 12021da177e4SLinus Torvalds *statp = rpc_system_err; 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds } else { 12051da177e4SLinus Torvalds dprintk("svc: calling dispatcher\n"); 12061da177e4SLinus Torvalds if (!versp->vs_dispatch(rqstp, statp)) { 12071da177e4SLinus Torvalds /* Release reply info */ 12081da177e4SLinus Torvalds if (procp->pc_release) 12091da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12101da177e4SLinus Torvalds goto dropit; 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds /* Check RPC status result */ 12151da177e4SLinus Torvalds if (*statp != rpc_success) 12161da177e4SLinus Torvalds resv->iov_len = ((void*)statp) - resv->iov_base + 4; 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds /* Release reply info */ 12191da177e4SLinus Torvalds if (procp->pc_release) 12201da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds if (procp->pc_encode == NULL) 12231da177e4SLinus Torvalds goto dropit; 12241da177e4SLinus Torvalds 12251da177e4SLinus Torvalds sendit: 12261da177e4SLinus Torvalds if (svc_authorise(rqstp)) 12271da177e4SLinus Torvalds goto dropit; 12281cad7ea6SRicardo Labiaga return 1; /* Caller can now send it */ 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds dropit: 12311da177e4SLinus Torvalds svc_authorise(rqstp); /* doesn't hurt to call this twice */ 12321da177e4SLinus Torvalds dprintk("svc: svc_process dropit\n"); 12331da177e4SLinus Torvalds return 0; 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds err_short_len: 1236354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "short len %Zd, dropping request\n", 1237354ecbb9SDr. David Alan Gilbert argv->iov_len); 123834e9a63bSNeilBrown 12391da177e4SLinus Torvalds goto dropit; /* drop request */ 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds err_bad_rpc: 12421da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 124376994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 124476994313SAlexey Dobriyan svc_putnl(resv, 0); /* RPC_MISMATCH */ 124576994313SAlexey Dobriyan svc_putnl(resv, 2); /* Only RPCv2 supported */ 124676994313SAlexey Dobriyan svc_putnl(resv, 2); 12471da177e4SLinus Torvalds goto sendit; 12481da177e4SLinus Torvalds 12491da177e4SLinus Torvalds err_bad_auth: 12501da177e4SLinus Torvalds dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); 12511da177e4SLinus Torvalds serv->sv_stats->rpcbadauth++; 12521da177e4SLinus Torvalds /* Restore write pointer to location of accept status: */ 12538f8e05c5SJ.Bruce Fields xdr_ressize_check(rqstp, reply_statp); 125476994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 125576994313SAlexey Dobriyan svc_putnl(resv, 1); /* AUTH_ERROR */ 125676994313SAlexey Dobriyan svc_putnl(resv, ntohl(auth_stat)); /* status */ 12571da177e4SLinus Torvalds goto sendit; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds err_bad_prog: 12609ba02638SAndreas Gruenbacher dprintk("svc: unknown program %d\n", prog); 12611da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 126276994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_UNAVAIL); 12631da177e4SLinus Torvalds goto sendit; 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds err_bad_vers: 1266354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", 12671a8eff6dSNeilBrown vers, prog, progp->pg_name); 126834e9a63bSNeilBrown 12691da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 127076994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_MISMATCH); 127176994313SAlexey Dobriyan svc_putnl(resv, progp->pg_lovers); 127276994313SAlexey Dobriyan svc_putnl(resv, progp->pg_hivers); 12731da177e4SLinus Torvalds goto sendit; 12741da177e4SLinus Torvalds 12751da177e4SLinus Torvalds err_bad_proc: 1276354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown procedure (%d)\n", proc); 127734e9a63bSNeilBrown 12781da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 127976994313SAlexey Dobriyan svc_putnl(resv, RPC_PROC_UNAVAIL); 12801da177e4SLinus Torvalds goto sendit; 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds err_garbage: 1283354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "failed to decode args\n"); 128434e9a63bSNeilBrown 12851da177e4SLinus Torvalds rpc_stat = rpc_garbage_args; 12861da177e4SLinus Torvalds err_bad: 12871da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 128876994313SAlexey Dobriyan svc_putnl(resv, ntohl(rpc_stat)); 12891da177e4SLinus Torvalds goto sendit; 12901da177e4SLinus Torvalds } 129124c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_process); 12927adae489SGreg Banks 12937adae489SGreg Banks /* 12941cad7ea6SRicardo Labiaga * Process the RPC request. 12951cad7ea6SRicardo Labiaga */ 12961cad7ea6SRicardo Labiaga int 12971cad7ea6SRicardo Labiaga svc_process(struct svc_rqst *rqstp) 12981cad7ea6SRicardo Labiaga { 12991cad7ea6SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 13001cad7ea6SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 13011cad7ea6SRicardo Labiaga struct svc_serv *serv = rqstp->rq_server; 13021cad7ea6SRicardo Labiaga u32 dir; 13031cad7ea6SRicardo Labiaga 13041cad7ea6SRicardo Labiaga /* 13051cad7ea6SRicardo Labiaga * Setup response xdr_buf. 13061cad7ea6SRicardo Labiaga * Initially it has just one page 13071cad7ea6SRicardo Labiaga */ 1308afc59400SJ. Bruce Fields rqstp->rq_next_page = &rqstp->rq_respages[1]; 13091cad7ea6SRicardo Labiaga resv->iov_base = page_address(rqstp->rq_respages[0]); 13101cad7ea6SRicardo Labiaga resv->iov_len = 0; 13111cad7ea6SRicardo Labiaga rqstp->rq_res.pages = rqstp->rq_respages + 1; 13121cad7ea6SRicardo Labiaga rqstp->rq_res.len = 0; 13131cad7ea6SRicardo Labiaga rqstp->rq_res.page_base = 0; 13141cad7ea6SRicardo Labiaga rqstp->rq_res.page_len = 0; 13151cad7ea6SRicardo Labiaga rqstp->rq_res.buflen = PAGE_SIZE; 13161cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_base = NULL; 13171cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_len = 0; 13181cad7ea6SRicardo Labiaga 13191cad7ea6SRicardo Labiaga rqstp->rq_xid = svc_getu32(argv); 13201cad7ea6SRicardo Labiaga 13211cad7ea6SRicardo Labiaga dir = svc_getnl(argv); 13221cad7ea6SRicardo Labiaga if (dir != 0) { 13231cad7ea6SRicardo Labiaga /* direction != CALL */ 13241cad7ea6SRicardo Labiaga svc_printk(rqstp, "bad direction %d, dropping request\n", dir); 13251cad7ea6SRicardo Labiaga serv->sv_stats->rpcbadfmt++; 13261cad7ea6SRicardo Labiaga svc_drop(rqstp); 13271cad7ea6SRicardo Labiaga return 0; 13281cad7ea6SRicardo Labiaga } 13291cad7ea6SRicardo Labiaga 13304b5b3ba1SAndy Adamson /* Returns 1 for send, 0 for drop */ 13314b5b3ba1SAndy Adamson if (svc_process_common(rqstp, argv, resv)) 13321cad7ea6SRicardo Labiaga return svc_send(rqstp); 13334b5b3ba1SAndy Adamson else { 13344b5b3ba1SAndy Adamson svc_drop(rqstp); 13354b5b3ba1SAndy Adamson return 0; 13364b5b3ba1SAndy Adamson } 13371cad7ea6SRicardo Labiaga } 13381cad7ea6SRicardo Labiaga 13399e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL) 13404d6bbb62SRicardo Labiaga /* 13414d6bbb62SRicardo Labiaga * Process a backchannel RPC request that arrived over an existing 13424d6bbb62SRicardo Labiaga * outbound connection 13434d6bbb62SRicardo Labiaga */ 13444d6bbb62SRicardo Labiaga int 13454d6bbb62SRicardo Labiaga bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, 13464d6bbb62SRicardo Labiaga struct svc_rqst *rqstp) 13474d6bbb62SRicardo Labiaga { 13484d6bbb62SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 13494d6bbb62SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 13504d6bbb62SRicardo Labiaga 13514d6bbb62SRicardo Labiaga /* Build the svc_rqst used by the common processing routine */ 13524a19de0fSAndy Adamson rqstp->rq_xprt = serv->sv_bc_xprt; 13534d6bbb62SRicardo Labiaga rqstp->rq_xid = req->rq_xid; 13544d6bbb62SRicardo Labiaga rqstp->rq_prot = req->rq_xprt->prot; 13554d6bbb62SRicardo Labiaga rqstp->rq_server = serv; 13564d6bbb62SRicardo Labiaga 13574d6bbb62SRicardo Labiaga rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); 13584d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); 13594d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); 13604d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); 13614d6bbb62SRicardo Labiaga 13624d6bbb62SRicardo Labiaga /* reset result send buffer "put" position */ 13634d6bbb62SRicardo Labiaga resv->iov_len = 0; 13644d6bbb62SRicardo Labiaga 13654d6bbb62SRicardo Labiaga if (rqstp->rq_prot != IPPROTO_TCP) { 13664d6bbb62SRicardo Labiaga printk(KERN_ERR "No support for Non-TCP transports!\n"); 13674d6bbb62SRicardo Labiaga BUG(); 13684d6bbb62SRicardo Labiaga } 13694d6bbb62SRicardo Labiaga 13704d6bbb62SRicardo Labiaga /* 13714d6bbb62SRicardo Labiaga * Skip the next two words because they've already been 13724d6bbb62SRicardo Labiaga * processed in the trasport 13734d6bbb62SRicardo Labiaga */ 13744d6bbb62SRicardo Labiaga svc_getu32(argv); /* XID */ 13754d6bbb62SRicardo Labiaga svc_getnl(argv); /* CALLDIR */ 13764d6bbb62SRicardo Labiaga 13774b5b3ba1SAndy Adamson /* Returns 1 for send, 0 for drop */ 13784b5b3ba1SAndy Adamson if (svc_process_common(rqstp, argv, resv)) { 13794b5b3ba1SAndy Adamson memcpy(&req->rq_snd_buf, &rqstp->rq_res, 13804b5b3ba1SAndy Adamson sizeof(req->rq_snd_buf)); 13814d6bbb62SRicardo Labiaga return bc_send(req); 13824b5b3ba1SAndy Adamson } else { 1383b3b02ae5STrond Myklebust /* drop request */ 1384b3b02ae5STrond Myklebust xprt_free_bc_request(req); 13854b5b3ba1SAndy Adamson return 0; 13864b5b3ba1SAndy Adamson } 13874d6bbb62SRicardo Labiaga } 13880d961aa9STrond Myklebust EXPORT_SYMBOL_GPL(bc_svc_process); 13899e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */ 13904d6bbb62SRicardo Labiaga 13911cad7ea6SRicardo Labiaga /* 13927adae489SGreg Banks * Return (transport-specific) limit on the rpc payload. 13937adae489SGreg Banks */ 13947adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp) 13957adae489SGreg Banks { 139649023155STom Tucker u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload; 13977adae489SGreg Banks 1398c6b0a9f8SNeilBrown if (rqstp->rq_server->sv_max_payload < max) 1399c6b0a9f8SNeilBrown max = rqstp->rq_server->sv_max_payload; 14007adae489SGreg Banks return max; 14017adae489SGreg Banks } 14027adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload); 1403