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 31860a0d9eSJeff Layton #include <trace/events/sunrpc.h> 32860a0d9eSJeff Layton 331da177e4SLinus Torvalds #define RPCDBG_FACILITY RPCDBG_SVCDSP 341da177e4SLinus Torvalds 355247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net); 367252d575SChuck Lever 3742a7fc4aSGreg Banks #define svc_serv_is_pooled(serv) ((serv)->sv_function) 3842a7fc4aSGreg Banks 391da177e4SLinus Torvalds /* 40bfd24160SGreg Banks * Mode for mapping cpus to pools. 41bfd24160SGreg Banks */ 42bfd24160SGreg Banks enum { 4342a7fc4aSGreg Banks SVC_POOL_AUTO = -1, /* choose one of the others */ 44bfd24160SGreg Banks SVC_POOL_GLOBAL, /* no mapping, just a single global pool 45bfd24160SGreg Banks * (legacy & UP mode) */ 46bfd24160SGreg Banks SVC_POOL_PERCPU, /* one pool per cpu */ 47bfd24160SGreg Banks SVC_POOL_PERNODE /* one pool per numa node */ 48bfd24160SGreg Banks }; 4942a7fc4aSGreg Banks #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL 50bfd24160SGreg Banks 51bfd24160SGreg Banks /* 52bfd24160SGreg Banks * Structure for mapping cpus to pools and vice versa. 53bfd24160SGreg Banks * Setup once during sunrpc initialisation. 54bfd24160SGreg Banks */ 55bfd24160SGreg Banks static struct svc_pool_map { 5642a7fc4aSGreg Banks int count; /* How many svc_servs use us */ 57bfd24160SGreg Banks int mode; /* Note: int not enum to avoid 58bfd24160SGreg Banks * warnings about "enumeration value 59bfd24160SGreg Banks * not handled in switch" */ 60bfd24160SGreg Banks unsigned int npools; 61bfd24160SGreg Banks unsigned int *pool_to; /* maps pool id to cpu or node */ 62bfd24160SGreg Banks unsigned int *to_pool; /* maps cpu or node to pool id */ 63bfd24160SGreg Banks } svc_pool_map = { 6442a7fc4aSGreg Banks .count = 0, 6542a7fc4aSGreg Banks .mode = SVC_POOL_DEFAULT 66bfd24160SGreg Banks }; 6742a7fc4aSGreg Banks static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ 68bfd24160SGreg Banks 6942a7fc4aSGreg Banks static int 7042a7fc4aSGreg Banks param_set_pool_mode(const char *val, struct kernel_param *kp) 7142a7fc4aSGreg Banks { 7242a7fc4aSGreg Banks int *ip = (int *)kp->arg; 7342a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 7442a7fc4aSGreg Banks int err; 7542a7fc4aSGreg Banks 7642a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 7742a7fc4aSGreg Banks 7842a7fc4aSGreg Banks err = -EBUSY; 7942a7fc4aSGreg Banks if (m->count) 8042a7fc4aSGreg Banks goto out; 8142a7fc4aSGreg Banks 8242a7fc4aSGreg Banks err = 0; 8342a7fc4aSGreg Banks if (!strncmp(val, "auto", 4)) 8442a7fc4aSGreg Banks *ip = SVC_POOL_AUTO; 8542a7fc4aSGreg Banks else if (!strncmp(val, "global", 6)) 8642a7fc4aSGreg Banks *ip = SVC_POOL_GLOBAL; 8742a7fc4aSGreg Banks else if (!strncmp(val, "percpu", 6)) 8842a7fc4aSGreg Banks *ip = SVC_POOL_PERCPU; 8942a7fc4aSGreg Banks else if (!strncmp(val, "pernode", 7)) 9042a7fc4aSGreg Banks *ip = SVC_POOL_PERNODE; 9142a7fc4aSGreg Banks else 9242a7fc4aSGreg Banks err = -EINVAL; 9342a7fc4aSGreg Banks 9442a7fc4aSGreg Banks out: 9542a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 9642a7fc4aSGreg Banks return err; 9742a7fc4aSGreg Banks } 9842a7fc4aSGreg Banks 9942a7fc4aSGreg Banks static int 10042a7fc4aSGreg Banks param_get_pool_mode(char *buf, struct kernel_param *kp) 10142a7fc4aSGreg Banks { 10242a7fc4aSGreg Banks int *ip = (int *)kp->arg; 10342a7fc4aSGreg Banks 10442a7fc4aSGreg Banks switch (*ip) 10542a7fc4aSGreg Banks { 10642a7fc4aSGreg Banks case SVC_POOL_AUTO: 10742a7fc4aSGreg Banks return strlcpy(buf, "auto", 20); 10842a7fc4aSGreg Banks case SVC_POOL_GLOBAL: 10942a7fc4aSGreg Banks return strlcpy(buf, "global", 20); 11042a7fc4aSGreg Banks case SVC_POOL_PERCPU: 11142a7fc4aSGreg Banks return strlcpy(buf, "percpu", 20); 11242a7fc4aSGreg Banks case SVC_POOL_PERNODE: 11342a7fc4aSGreg Banks return strlcpy(buf, "pernode", 20); 11442a7fc4aSGreg Banks default: 11542a7fc4aSGreg Banks return sprintf(buf, "%d", *ip); 11642a7fc4aSGreg Banks } 11742a7fc4aSGreg Banks } 11842a7fc4aSGreg Banks 11942a7fc4aSGreg Banks module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode, 12042a7fc4aSGreg Banks &svc_pool_map.mode, 0644); 121bfd24160SGreg Banks 122bfd24160SGreg Banks /* 123bfd24160SGreg Banks * Detect best pool mapping mode heuristically, 124bfd24160SGreg Banks * according to the machine's topology. 125bfd24160SGreg Banks */ 126bfd24160SGreg Banks static int 127bfd24160SGreg Banks svc_pool_map_choose_mode(void) 128bfd24160SGreg Banks { 129bfd24160SGreg Banks unsigned int node; 130bfd24160SGreg Banks 13162bc62a8SChristoph Lameter if (nr_online_nodes > 1) { 132bfd24160SGreg Banks /* 133bfd24160SGreg Banks * Actually have multiple NUMA nodes, 134bfd24160SGreg Banks * so split pools on NUMA node boundaries 135bfd24160SGreg Banks */ 136bfd24160SGreg Banks return SVC_POOL_PERNODE; 137bfd24160SGreg Banks } 138bfd24160SGreg Banks 13972c33688SH Hartley Sweeten node = first_online_node; 140bfd24160SGreg Banks if (nr_cpus_node(node) > 2) { 141bfd24160SGreg Banks /* 142bfd24160SGreg Banks * Non-trivial SMP, or CONFIG_NUMA on 143bfd24160SGreg Banks * non-NUMA hardware, e.g. with a generic 144bfd24160SGreg Banks * x86_64 kernel on Xeons. In this case we 145bfd24160SGreg Banks * want to divide the pools on cpu boundaries. 146bfd24160SGreg Banks */ 147bfd24160SGreg Banks return SVC_POOL_PERCPU; 148bfd24160SGreg Banks } 149bfd24160SGreg Banks 150bfd24160SGreg Banks /* default: one global pool */ 151bfd24160SGreg Banks return SVC_POOL_GLOBAL; 152bfd24160SGreg Banks } 153bfd24160SGreg Banks 154bfd24160SGreg Banks /* 155bfd24160SGreg Banks * Allocate the to_pool[] and pool_to[] arrays. 156bfd24160SGreg Banks * Returns 0 on success or an errno. 157bfd24160SGreg Banks */ 158bfd24160SGreg Banks static int 159bfd24160SGreg Banks svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) 160bfd24160SGreg Banks { 161bfd24160SGreg Banks m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 162bfd24160SGreg Banks if (!m->to_pool) 163bfd24160SGreg Banks goto fail; 164bfd24160SGreg Banks m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 165bfd24160SGreg Banks if (!m->pool_to) 166bfd24160SGreg Banks goto fail_free; 167bfd24160SGreg Banks 168bfd24160SGreg Banks return 0; 169bfd24160SGreg Banks 170bfd24160SGreg Banks fail_free: 171bfd24160SGreg Banks kfree(m->to_pool); 17261c8504cSJ. Bruce Fields m->to_pool = NULL; 173bfd24160SGreg Banks fail: 174bfd24160SGreg Banks return -ENOMEM; 175bfd24160SGreg Banks } 176bfd24160SGreg Banks 177bfd24160SGreg Banks /* 178bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERCPU mode. 179bfd24160SGreg Banks * Returns number of pools or <0 on error. 180bfd24160SGreg Banks */ 181bfd24160SGreg Banks static int 182bfd24160SGreg Banks svc_pool_map_init_percpu(struct svc_pool_map *m) 183bfd24160SGreg Banks { 18453b8a315SChristoph Lameter unsigned int maxpools = nr_cpu_ids; 185bfd24160SGreg Banks unsigned int pidx = 0; 186bfd24160SGreg Banks unsigned int cpu; 187bfd24160SGreg Banks int err; 188bfd24160SGreg Banks 189bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 190bfd24160SGreg Banks if (err) 191bfd24160SGreg Banks return err; 192bfd24160SGreg Banks 193bfd24160SGreg Banks for_each_online_cpu(cpu) { 194eb63192bSDan Carpenter BUG_ON(pidx >= maxpools); 195bfd24160SGreg Banks m->to_pool[cpu] = pidx; 196bfd24160SGreg Banks m->pool_to[pidx] = cpu; 197bfd24160SGreg Banks pidx++; 198bfd24160SGreg Banks } 199bfd24160SGreg Banks /* cpus brought online later all get mapped to pool0, sorry */ 200bfd24160SGreg Banks 201bfd24160SGreg Banks return pidx; 202bfd24160SGreg Banks }; 203bfd24160SGreg Banks 204bfd24160SGreg Banks 205bfd24160SGreg Banks /* 206bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERNODE mode. 207bfd24160SGreg Banks * Returns number of pools or <0 on error. 208bfd24160SGreg Banks */ 209bfd24160SGreg Banks static int 210bfd24160SGreg Banks svc_pool_map_init_pernode(struct svc_pool_map *m) 211bfd24160SGreg Banks { 21274c7aa8bSChristoph Lameter unsigned int maxpools = nr_node_ids; 213bfd24160SGreg Banks unsigned int pidx = 0; 214bfd24160SGreg Banks unsigned int node; 215bfd24160SGreg Banks int err; 216bfd24160SGreg Banks 217bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 218bfd24160SGreg Banks if (err) 219bfd24160SGreg Banks return err; 220bfd24160SGreg Banks 221bfd24160SGreg Banks for_each_node_with_cpus(node) { 222bfd24160SGreg Banks /* some architectures (e.g. SN2) have cpuless nodes */ 223bfd24160SGreg Banks BUG_ON(pidx > maxpools); 224bfd24160SGreg Banks m->to_pool[node] = pidx; 225bfd24160SGreg Banks m->pool_to[pidx] = node; 226bfd24160SGreg Banks pidx++; 227bfd24160SGreg Banks } 228bfd24160SGreg Banks /* nodes brought online later all get mapped to pool0, sorry */ 229bfd24160SGreg Banks 230bfd24160SGreg Banks return pidx; 231bfd24160SGreg Banks } 232bfd24160SGreg Banks 233bfd24160SGreg Banks 234bfd24160SGreg Banks /* 23542a7fc4aSGreg Banks * Add a reference to the global map of cpus to pools (and 23642a7fc4aSGreg Banks * vice versa). Initialise the map if we're the first user. 23742a7fc4aSGreg Banks * Returns the number of pools. 238bfd24160SGreg Banks */ 239bfd24160SGreg Banks static unsigned int 24042a7fc4aSGreg Banks svc_pool_map_get(void) 241bfd24160SGreg Banks { 242bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 243bfd24160SGreg Banks int npools = -1; 244bfd24160SGreg Banks 24542a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 246bfd24160SGreg Banks 24742a7fc4aSGreg Banks if (m->count++) { 24842a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 24942a7fc4aSGreg Banks return m->npools; 25042a7fc4aSGreg Banks } 25142a7fc4aSGreg Banks 25242a7fc4aSGreg Banks if (m->mode == SVC_POOL_AUTO) 253bfd24160SGreg Banks m->mode = svc_pool_map_choose_mode(); 254bfd24160SGreg Banks 255bfd24160SGreg Banks switch (m->mode) { 256bfd24160SGreg Banks case SVC_POOL_PERCPU: 257bfd24160SGreg Banks npools = svc_pool_map_init_percpu(m); 258bfd24160SGreg Banks break; 259bfd24160SGreg Banks case SVC_POOL_PERNODE: 260bfd24160SGreg Banks npools = svc_pool_map_init_pernode(m); 261bfd24160SGreg Banks break; 262bfd24160SGreg Banks } 263bfd24160SGreg Banks 264bfd24160SGreg Banks if (npools < 0) { 265bfd24160SGreg Banks /* default, or memory allocation failure */ 266bfd24160SGreg Banks npools = 1; 267bfd24160SGreg Banks m->mode = SVC_POOL_GLOBAL; 268bfd24160SGreg Banks } 269bfd24160SGreg Banks m->npools = npools; 270bfd24160SGreg Banks 27142a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 272bfd24160SGreg Banks return m->npools; 273bfd24160SGreg Banks } 274bfd24160SGreg Banks 27542a7fc4aSGreg Banks 27642a7fc4aSGreg Banks /* 27742a7fc4aSGreg Banks * Drop a reference to the global map of cpus to pools. 27842a7fc4aSGreg Banks * When the last reference is dropped, the map data is 27942a7fc4aSGreg Banks * freed; this allows the sysadmin to change the pool 28042a7fc4aSGreg Banks * mode using the pool_mode module option without 28142a7fc4aSGreg Banks * rebooting or re-loading sunrpc.ko. 28242a7fc4aSGreg Banks */ 28342a7fc4aSGreg Banks static void 28442a7fc4aSGreg Banks svc_pool_map_put(void) 28542a7fc4aSGreg Banks { 28642a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 28742a7fc4aSGreg Banks 28842a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 28942a7fc4aSGreg Banks 29042a7fc4aSGreg Banks if (!--m->count) { 29142a7fc4aSGreg Banks kfree(m->to_pool); 29261c8504cSJ. Bruce Fields m->to_pool = NULL; 29342a7fc4aSGreg Banks kfree(m->pool_to); 29461c8504cSJ. Bruce Fields m->pool_to = NULL; 29542a7fc4aSGreg Banks m->npools = 0; 29642a7fc4aSGreg Banks } 29742a7fc4aSGreg Banks 29842a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 29942a7fc4aSGreg Banks } 30042a7fc4aSGreg Banks 30142a7fc4aSGreg Banks 30211fd165cSEric Dumazet static int svc_pool_map_get_node(unsigned int pidx) 30311fd165cSEric Dumazet { 30411fd165cSEric Dumazet const struct svc_pool_map *m = &svc_pool_map; 30511fd165cSEric Dumazet 30611fd165cSEric Dumazet if (m->count) { 30711fd165cSEric Dumazet if (m->mode == SVC_POOL_PERCPU) 30811fd165cSEric Dumazet return cpu_to_node(m->pool_to[pidx]); 30911fd165cSEric Dumazet if (m->mode == SVC_POOL_PERNODE) 31011fd165cSEric Dumazet return m->pool_to[pidx]; 31111fd165cSEric Dumazet } 31211fd165cSEric Dumazet return NUMA_NO_NODE; 31311fd165cSEric Dumazet } 314bfd24160SGreg Banks /* 3159867d76cSJeff Layton * Set the given thread's cpus_allowed mask so that it 316bfd24160SGreg Banks * will only run on cpus in the given pool. 317bfd24160SGreg Banks */ 3189867d76cSJeff Layton static inline void 3199867d76cSJeff Layton svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) 320bfd24160SGreg Banks { 321bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 3229867d76cSJeff Layton unsigned int node = m->pool_to[pidx]; 323bfd24160SGreg Banks 324bfd24160SGreg Banks /* 325bfd24160SGreg Banks * The caller checks for sv_nrpools > 1, which 32642a7fc4aSGreg Banks * implies that we've been initialized. 327bfd24160SGreg Banks */ 3281bd58aafSWeston Andros Adamson WARN_ON_ONCE(m->count == 0); 3291bd58aafSWeston Andros Adamson if (m->count == 0) 3301bd58aafSWeston Andros Adamson return; 331bfd24160SGreg Banks 3329867d76cSJeff Layton switch (m->mode) { 333bfd24160SGreg Banks case SVC_POOL_PERCPU: 334c5f59f08SMike Travis { 335aa85ea5bSRusty Russell set_cpus_allowed_ptr(task, cpumask_of(node)); 3369867d76cSJeff Layton break; 337c5f59f08SMike Travis } 338bfd24160SGreg Banks case SVC_POOL_PERNODE: 339c5f59f08SMike Travis { 340a70f7302SRusty Russell set_cpus_allowed_ptr(task, cpumask_of_node(node)); 3419867d76cSJeff Layton break; 342bfd24160SGreg Banks } 343bfd24160SGreg Banks } 344c5f59f08SMike Travis } 345bfd24160SGreg Banks 346bfd24160SGreg Banks /* 347bfd24160SGreg Banks * Use the mapping mode to choose a pool for a given CPU. 348bfd24160SGreg Banks * Used when enqueueing an incoming RPC. Always returns 349bfd24160SGreg Banks * a non-NULL pool pointer. 350bfd24160SGreg Banks */ 351bfd24160SGreg Banks struct svc_pool * 352bfd24160SGreg Banks svc_pool_for_cpu(struct svc_serv *serv, int cpu) 353bfd24160SGreg Banks { 354bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 355bfd24160SGreg Banks unsigned int pidx = 0; 356bfd24160SGreg Banks 357bfd24160SGreg Banks /* 35842a7fc4aSGreg Banks * An uninitialised map happens in a pure client when 359bfd24160SGreg Banks * lockd is brought up, so silently treat it the 360bfd24160SGreg Banks * same as SVC_POOL_GLOBAL. 361bfd24160SGreg Banks */ 36242a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) { 363bfd24160SGreg Banks switch (m->mode) { 364bfd24160SGreg Banks case SVC_POOL_PERCPU: 365bfd24160SGreg Banks pidx = m->to_pool[cpu]; 366bfd24160SGreg Banks break; 367bfd24160SGreg Banks case SVC_POOL_PERNODE: 368bfd24160SGreg Banks pidx = m->to_pool[cpu_to_node(cpu)]; 369bfd24160SGreg Banks break; 370bfd24160SGreg Banks } 37142a7fc4aSGreg Banks } 372bfd24160SGreg Banks return &serv->sv_pools[pidx % serv->sv_nrpools]; 373bfd24160SGreg Banks } 374bfd24160SGreg Banks 375bb2224dfSStanislav Kinsbursky int svc_rpcb_setup(struct svc_serv *serv, struct net *net) 376d9908560SStanislav Kinsbursky { 377d9908560SStanislav Kinsbursky int err; 378d9908560SStanislav Kinsbursky 379bee42f68SStanislav Kinsbursky err = rpcb_create_local(net); 380d9908560SStanislav Kinsbursky if (err) 381d9908560SStanislav Kinsbursky return err; 382d9908560SStanislav Kinsbursky 383d9908560SStanislav Kinsbursky /* Remove any stale portmap registrations */ 384bee42f68SStanislav Kinsbursky svc_unregister(serv, net); 385d9908560SStanislav Kinsbursky return 0; 386d9908560SStanislav Kinsbursky } 387bb2224dfSStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_setup); 388d9908560SStanislav Kinsbursky 3895ecebb7cSStanislav Kinsbursky void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) 390d9908560SStanislav Kinsbursky { 3915ecebb7cSStanislav Kinsbursky svc_unregister(serv, net); 3925ecebb7cSStanislav Kinsbursky rpcb_put_local(net); 393d9908560SStanislav Kinsbursky } 39416d05870SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); 395d9908560SStanislav Kinsbursky 396d9908560SStanislav Kinsbursky static int svc_uses_rpcbind(struct svc_serv *serv) 397d9908560SStanislav Kinsbursky { 398d9908560SStanislav Kinsbursky struct svc_program *progp; 399d9908560SStanislav Kinsbursky unsigned int i; 400d9908560SStanislav Kinsbursky 401d9908560SStanislav Kinsbursky for (progp = serv->sv_program; progp; progp = progp->pg_next) { 402d9908560SStanislav Kinsbursky for (i = 0; i < progp->pg_nvers; i++) { 403d9908560SStanislav Kinsbursky if (progp->pg_vers[i] == NULL) 404d9908560SStanislav Kinsbursky continue; 405d9908560SStanislav Kinsbursky if (progp->pg_vers[i]->vs_hidden == 0) 406d9908560SStanislav Kinsbursky return 1; 407d9908560SStanislav Kinsbursky } 408d9908560SStanislav Kinsbursky } 409d9908560SStanislav Kinsbursky 410d9908560SStanislav Kinsbursky return 0; 411d9908560SStanislav Kinsbursky } 412bfd24160SGreg Banks 4139793f7c8SStanislav Kinsbursky int svc_bind(struct svc_serv *serv, struct net *net) 4149793f7c8SStanislav Kinsbursky { 4159793f7c8SStanislav Kinsbursky if (!svc_uses_rpcbind(serv)) 4169793f7c8SStanislav Kinsbursky return 0; 4179793f7c8SStanislav Kinsbursky return svc_rpcb_setup(serv, net); 4189793f7c8SStanislav Kinsbursky } 4199793f7c8SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_bind); 4209793f7c8SStanislav Kinsbursky 421bfd24160SGreg Banks /* 4221da177e4SLinus Torvalds * Create an RPC service 4231da177e4SLinus Torvalds */ 424a7455442SGreg Banks static struct svc_serv * 425a7455442SGreg Banks __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, 4265ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net)) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds struct svc_serv *serv; 429ea339d46SChuck Lever unsigned int vers; 4301da177e4SLinus Torvalds unsigned int xdrsize; 4313262c816SGreg Banks unsigned int i; 4321da177e4SLinus Torvalds 4330da974f4SPanagiotis Issaris if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) 4341da177e4SLinus Torvalds return NULL; 4359ba02638SAndreas Gruenbacher serv->sv_name = prog->pg_name; 4361da177e4SLinus Torvalds serv->sv_program = prog; 4371da177e4SLinus Torvalds serv->sv_nrthreads = 1; 4381da177e4SLinus Torvalds serv->sv_stats = prog->pg_stats; 439c6b0a9f8SNeilBrown if (bufsize > RPCSVC_MAXPAYLOAD) 440c6b0a9f8SNeilBrown bufsize = RPCSVC_MAXPAYLOAD; 441c6b0a9f8SNeilBrown serv->sv_max_payload = bufsize? bufsize : 4096; 442c6b0a9f8SNeilBrown serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); 443bc591ccfSNeilBrown serv->sv_shutdown = shutdown; 4441da177e4SLinus Torvalds xdrsize = 0; 4459ba02638SAndreas Gruenbacher while (prog) { 4469ba02638SAndreas Gruenbacher prog->pg_lovers = prog->pg_nvers-1; 4471da177e4SLinus Torvalds for (vers=0; vers<prog->pg_nvers ; vers++) 4481da177e4SLinus Torvalds if (prog->pg_vers[vers]) { 4491da177e4SLinus Torvalds prog->pg_hivers = vers; 4501da177e4SLinus Torvalds if (prog->pg_lovers > vers) 4511da177e4SLinus Torvalds prog->pg_lovers = vers; 4521da177e4SLinus Torvalds if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) 4531da177e4SLinus Torvalds xdrsize = prog->pg_vers[vers]->vs_xdrsize; 4541da177e4SLinus Torvalds } 4559ba02638SAndreas Gruenbacher prog = prog->pg_next; 4569ba02638SAndreas Gruenbacher } 4571da177e4SLinus Torvalds serv->sv_xdrsize = xdrsize; 4581da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_tempsocks); 4591da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_permsocks); 46036bdfc8bSGreg Banks init_timer(&serv->sv_temptimer); 4611da177e4SLinus Torvalds spin_lock_init(&serv->sv_lock); 4621da177e4SLinus Torvalds 463a7455442SGreg Banks serv->sv_nrpools = npools; 4643262c816SGreg Banks serv->sv_pools = 465cd861280SRobert P. J. Day kcalloc(serv->sv_nrpools, sizeof(struct svc_pool), 4663262c816SGreg Banks GFP_KERNEL); 4673262c816SGreg Banks if (!serv->sv_pools) { 4683262c816SGreg Banks kfree(serv); 4693262c816SGreg Banks return NULL; 4703262c816SGreg Banks } 4713262c816SGreg Banks 4723262c816SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 4733262c816SGreg Banks struct svc_pool *pool = &serv->sv_pools[i]; 4743262c816SGreg Banks 47546121cf7SChuck Lever dprintk("svc: initialising pool %u for %s\n", 4763262c816SGreg Banks i, serv->sv_name); 4773262c816SGreg Banks 4783262c816SGreg Banks pool->sp_id = i; 4793262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_sockets); 480a7455442SGreg Banks INIT_LIST_HEAD(&pool->sp_all_threads); 4813262c816SGreg Banks spin_lock_init(&pool->sp_lock); 4823262c816SGreg Banks } 4833262c816SGreg Banks 4841da177e4SLinus Torvalds return serv; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds 487a7455442SGreg Banks struct svc_serv * 488a7455442SGreg Banks svc_create(struct svc_program *prog, unsigned int bufsize, 4895ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net)) 490a7455442SGreg Banks { 49149a9072fSChuck Lever return __svc_create(prog, bufsize, /*npools*/1, shutdown); 492a7455442SGreg Banks } 49324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create); 494a7455442SGreg Banks 495a7455442SGreg Banks struct svc_serv * 496a7455442SGreg Banks svc_create_pooled(struct svc_program *prog, unsigned int bufsize, 4975ecebb7cSStanislav Kinsbursky void (*shutdown)(struct svc_serv *serv, struct net *net), 498a75c5d01SJeff Layton svc_thread_fn func, struct module *mod) 499a7455442SGreg Banks { 500a7455442SGreg Banks struct svc_serv *serv; 50142a7fc4aSGreg Banks unsigned int npools = svc_pool_map_get(); 502a7455442SGreg Banks 50349a9072fSChuck Lever serv = __svc_create(prog, bufsize, npools, shutdown); 504067f96efSJeff Layton if (!serv) 505067f96efSJeff Layton goto out_err; 506a7455442SGreg Banks 507a7455442SGreg Banks serv->sv_function = func; 508a7455442SGreg Banks serv->sv_module = mod; 509a7455442SGreg Banks return serv; 510067f96efSJeff Layton out_err: 511067f96efSJeff Layton svc_pool_map_put(); 512067f96efSJeff Layton return NULL; 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 serv->sv_nrthreads++; 616b1691bc0SJeff Layton __set_bit(RQ_BUSY, &rqstp->rq_flags); 617b1691bc0SJeff Layton spin_lock_init(&rqstp->rq_lock); 618b1691bc0SJeff Layton rqstp->rq_server = serv; 619b1691bc0SJeff Layton rqstp->rq_pool = pool; 6200113ab34SJeff Layton spin_lock_bh(&pool->sp_lock); 6210113ab34SJeff Layton pool->sp_nrthreads++; 62281244386SJeff Layton list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); 6230113ab34SJeff Layton spin_unlock_bh(&pool->sp_lock); 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); 68881244386SJeff Layton set_bit(RQ_VICTIM, &rqstp->rq_flags); 68981244386SJeff Layton list_del_rcu(&rqstp->rq_all); 690a7455442SGreg Banks task = rqstp->rq_task; 691a7455442SGreg Banks } 692a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 693a7455442SGreg Banks 694a7455442SGreg Banks return task; 695a7455442SGreg Banks } 696a7455442SGreg Banks 697a7455442SGreg Banks /* 698a7455442SGreg Banks * Create or destroy enough new threads to make the number 699a7455442SGreg Banks * of threads the given number. If `pool' is non-NULL, applies 700a7455442SGreg Banks * only to threads in that pool, otherwise round-robins between 70194cf3179SJ. Bruce Fields * all pools. Caller must ensure that mutual exclusion between this and 70294cf3179SJ. Bruce Fields * server startup or shutdown. 703a7455442SGreg Banks * 704a7455442SGreg Banks * Destroying threads relies on the service threads filling in 705a7455442SGreg Banks * rqstp->rq_task, which only the nfs ones do. Assumes the serv 706a7455442SGreg Banks * has been created using svc_create_pooled(). 707a7455442SGreg Banks * 708a7455442SGreg Banks * Based on code that used to be in nfsd_svc() but tweaked 709a7455442SGreg Banks * to be pool-aware. 710a7455442SGreg Banks */ 711a7455442SGreg Banks int 712a7455442SGreg Banks svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 713a7455442SGreg Banks { 7149867d76cSJeff Layton struct svc_rqst *rqstp; 7159867d76cSJeff Layton struct task_struct *task; 7169867d76cSJeff Layton struct svc_pool *chosen_pool; 717a7455442SGreg Banks int error = 0; 718a7455442SGreg Banks unsigned int state = serv->sv_nrthreads-1; 71911fd165cSEric Dumazet int node; 720a7455442SGreg Banks 721a7455442SGreg Banks if (pool == NULL) { 722a7455442SGreg Banks /* The -1 assumes caller has done a svc_get() */ 723a7455442SGreg Banks nrservs -= (serv->sv_nrthreads-1); 724a7455442SGreg Banks } else { 725a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 726a7455442SGreg Banks nrservs -= pool->sp_nrthreads; 727a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 728a7455442SGreg Banks } 729a7455442SGreg Banks 730a7455442SGreg Banks /* create new threads */ 731a7455442SGreg Banks while (nrservs > 0) { 732a7455442SGreg Banks nrservs--; 7339867d76cSJeff Layton chosen_pool = choose_pool(serv, pool, &state); 7349867d76cSJeff Layton 73511fd165cSEric Dumazet node = svc_pool_map_get_node(chosen_pool->sp_id); 73611fd165cSEric Dumazet rqstp = svc_prepare_thread(serv, chosen_pool, node); 7379867d76cSJeff Layton if (IS_ERR(rqstp)) { 7389867d76cSJeff Layton error = PTR_ERR(rqstp); 739a7455442SGreg Banks break; 740a7455442SGreg Banks } 7419867d76cSJeff Layton 7429867d76cSJeff Layton __module_get(serv->sv_module); 74311fd165cSEric Dumazet task = kthread_create_on_node(serv->sv_function, rqstp, 744f170168bSKees Cook node, "%s", serv->sv_name); 7459867d76cSJeff Layton if (IS_ERR(task)) { 7469867d76cSJeff Layton error = PTR_ERR(task); 7479867d76cSJeff Layton module_put(serv->sv_module); 7489867d76cSJeff Layton svc_exit_thread(rqstp); 7499867d76cSJeff Layton break; 7509867d76cSJeff Layton } 7519867d76cSJeff Layton 7529867d76cSJeff Layton rqstp->rq_task = task; 7539867d76cSJeff Layton if (serv->sv_nrpools > 1) 7549867d76cSJeff Layton svc_pool_map_set_cpumask(task, chosen_pool->sp_id); 7559867d76cSJeff Layton 7569867d76cSJeff Layton svc_sock_update_bufs(serv); 7579867d76cSJeff Layton wake_up_process(task); 758a7455442SGreg Banks } 759a7455442SGreg Banks /* destroy old threads */ 760a7455442SGreg Banks while (nrservs < 0 && 7619867d76cSJeff Layton (task = choose_victim(serv, pool, &state)) != NULL) { 762a75c5d01SJeff Layton send_sig(SIGINT, task, 1); 763a7455442SGreg Banks nrservs++; 764a7455442SGreg Banks } 765a7455442SGreg Banks 766a7455442SGreg Banks return error; 767a7455442SGreg Banks } 76824c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_set_num_threads); 769a7455442SGreg Banks 770a7455442SGreg Banks /* 7713c519914SJeff Layton * Called from a server thread as it's exiting. Caller must hold the "service 7723c519914SJeff Layton * mutex" for the service. 7731da177e4SLinus Torvalds */ 7741da177e4SLinus Torvalds void 7751da177e4SLinus Torvalds svc_exit_thread(struct svc_rqst *rqstp) 7761da177e4SLinus Torvalds { 7771da177e4SLinus Torvalds struct svc_serv *serv = rqstp->rq_server; 7783262c816SGreg Banks struct svc_pool *pool = rqstp->rq_pool; 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds svc_release_buffer(rqstp); 7811da177e4SLinus Torvalds kfree(rqstp->rq_resp); 7821da177e4SLinus Torvalds kfree(rqstp->rq_argp); 7831da177e4SLinus Torvalds kfree(rqstp->rq_auth_data); 7843262c816SGreg Banks 7853262c816SGreg Banks spin_lock_bh(&pool->sp_lock); 7863262c816SGreg Banks pool->sp_nrthreads--; 78781244386SJeff Layton if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags)) 78881244386SJeff Layton list_del_rcu(&rqstp->rq_all); 7893262c816SGreg Banks spin_unlock_bh(&pool->sp_lock); 7903262c816SGreg Banks 79181244386SJeff Layton kfree_rcu(rqstp, rq_rcu_head); 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds /* Release the server */ 7941da177e4SLinus Torvalds if (serv) 7951da177e4SLinus Torvalds svc_destroy(serv); 7961da177e4SLinus Torvalds } 79724c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_exit_thread); 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds /* 8002c7eb0b2SChuck Lever * Register an "inet" protocol family netid with the local 8012c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 802a26cfad6SChuck Lever * 8032c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8042c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 805a26cfad6SChuck Lever * 8062c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8072c7eb0b2SChuck Lever * if any error occurs. 8081da177e4SLinus Torvalds */ 8095247fab5SStanislav Kinsbursky static int __svc_rpcb_register4(struct net *net, const u32 program, 8105247fab5SStanislav Kinsbursky const u32 version, 811a26cfad6SChuck Lever const unsigned short protocol, 812a26cfad6SChuck Lever const unsigned short port) 813a26cfad6SChuck Lever { 814cadc0fa5SChuck Lever const struct sockaddr_in sin = { 815a26cfad6SChuck Lever .sin_family = AF_INET, 816a26cfad6SChuck Lever .sin_addr.s_addr = htonl(INADDR_ANY), 817a26cfad6SChuck Lever .sin_port = htons(port), 818a26cfad6SChuck Lever }; 819cadc0fa5SChuck Lever const char *netid; 820cadc0fa5SChuck Lever int error; 8212c7eb0b2SChuck Lever 8222c7eb0b2SChuck Lever switch (protocol) { 8232c7eb0b2SChuck Lever case IPPROTO_UDP: 8242c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP; 8252c7eb0b2SChuck Lever break; 8262c7eb0b2SChuck Lever case IPPROTO_TCP: 8272c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP; 8282c7eb0b2SChuck Lever break; 8292c7eb0b2SChuck Lever default: 830ba5c35e0SChuck Lever return -ENOPROTOOPT; 8312c7eb0b2SChuck Lever } 8322c7eb0b2SChuck Lever 8335247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 834cadc0fa5SChuck Lever (const struct sockaddr *)&sin, netid); 835cadc0fa5SChuck Lever 836cadc0fa5SChuck Lever /* 837cadc0fa5SChuck Lever * User space didn't support rpcbind v4, so retry this 838cadc0fa5SChuck Lever * registration request with the legacy rpcbind v2 protocol. 839cadc0fa5SChuck Lever */ 840cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 8415247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, protocol, port); 842cadc0fa5SChuck Lever 843cadc0fa5SChuck Lever return error; 8442c7eb0b2SChuck Lever } 8452c7eb0b2SChuck Lever 846dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 8472c7eb0b2SChuck Lever /* 8482c7eb0b2SChuck Lever * Register an "inet6" protocol family netid with the local 8492c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 8502c7eb0b2SChuck Lever * 8512c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8522c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 8532c7eb0b2SChuck Lever * 8542c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8552c7eb0b2SChuck Lever * if any error occurs. 8562c7eb0b2SChuck Lever */ 8575247fab5SStanislav Kinsbursky static int __svc_rpcb_register6(struct net *net, const u32 program, 8585247fab5SStanislav Kinsbursky const u32 version, 8592c7eb0b2SChuck Lever const unsigned short protocol, 8602c7eb0b2SChuck Lever const unsigned short port) 8612c7eb0b2SChuck Lever { 862cadc0fa5SChuck Lever const struct sockaddr_in6 sin6 = { 863a26cfad6SChuck Lever .sin6_family = AF_INET6, 864a26cfad6SChuck Lever .sin6_addr = IN6ADDR_ANY_INIT, 865a26cfad6SChuck Lever .sin6_port = htons(port), 866a26cfad6SChuck Lever }; 867cadc0fa5SChuck Lever const char *netid; 868cadc0fa5SChuck Lever int error; 869a26cfad6SChuck Lever 8702c7eb0b2SChuck Lever switch (protocol) { 8712c7eb0b2SChuck Lever case IPPROTO_UDP: 8722c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP6; 8732c7eb0b2SChuck Lever break; 8742c7eb0b2SChuck Lever case IPPROTO_TCP: 8752c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP6; 8762c7eb0b2SChuck Lever break; 8772c7eb0b2SChuck Lever default: 878ba5c35e0SChuck Lever return -ENOPROTOOPT; 8792c7eb0b2SChuck Lever } 8802c7eb0b2SChuck Lever 8815247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 882cadc0fa5SChuck Lever (const struct sockaddr *)&sin6, netid); 883cadc0fa5SChuck Lever 884cadc0fa5SChuck Lever /* 885cadc0fa5SChuck Lever * User space didn't support rpcbind version 4, so we won't 886cadc0fa5SChuck Lever * use a PF_INET6 listener. 887cadc0fa5SChuck Lever */ 888cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 889cadc0fa5SChuck Lever error = -EAFNOSUPPORT; 890cadc0fa5SChuck Lever 891cadc0fa5SChuck Lever return error; 8922c7eb0b2SChuck Lever } 893dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 8942c7eb0b2SChuck Lever 8952c7eb0b2SChuck Lever /* 8962c7eb0b2SChuck Lever * Register a kernel RPC service via rpcbind version 4. 8972c7eb0b2SChuck Lever * 8982c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8992c7eb0b2SChuck Lever * if any error occurs. 9002c7eb0b2SChuck Lever */ 9015247fab5SStanislav Kinsbursky static int __svc_register(struct net *net, const char *progname, 902363f724cSChuck Lever const u32 program, const u32 version, 9034b62e58cSChuck Lever const int family, 9042c7eb0b2SChuck Lever const unsigned short protocol, 9052c7eb0b2SChuck Lever const unsigned short port) 9062c7eb0b2SChuck Lever { 907363f724cSChuck Lever int error = -EAFNOSUPPORT; 9082c7eb0b2SChuck Lever 909a26cfad6SChuck Lever switch (family) { 9104b62e58cSChuck Lever case PF_INET: 9115247fab5SStanislav Kinsbursky error = __svc_rpcb_register4(net, program, version, 9122c7eb0b2SChuck Lever protocol, port); 913cadc0fa5SChuck Lever break; 914dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 9154b62e58cSChuck Lever case PF_INET6: 9165247fab5SStanislav Kinsbursky error = __svc_rpcb_register6(net, program, version, 9172c7eb0b2SChuck Lever protocol, port); 918dfd56b8bSEric Dumazet #endif 9192c7eb0b2SChuck Lever } 9202c7eb0b2SChuck Lever 921a26cfad6SChuck Lever return error; 922a26cfad6SChuck Lever } 923a26cfad6SChuck Lever 924a26cfad6SChuck Lever /** 925a26cfad6SChuck Lever * svc_register - register an RPC service with the local portmapper 926a26cfad6SChuck Lever * @serv: svc_serv struct for the service to register 9275247fab5SStanislav Kinsbursky * @net: net namespace for the service to register 9284b62e58cSChuck Lever * @family: protocol family of service's listener socket 929a26cfad6SChuck Lever * @proto: transport protocol number to advertise 930a26cfad6SChuck Lever * @port: port to advertise 931a26cfad6SChuck Lever * 9324b62e58cSChuck Lever * Service is registered for any address in the passed-in protocol family 933a26cfad6SChuck Lever */ 9345247fab5SStanislav Kinsbursky int svc_register(const struct svc_serv *serv, struct net *net, 9355247fab5SStanislav Kinsbursky const int family, const unsigned short proto, 9365247fab5SStanislav Kinsbursky const unsigned short port) 9371da177e4SLinus Torvalds { 9381da177e4SLinus Torvalds struct svc_program *progp; 9397e55b59bSKinglong Mee struct svc_version *vers; 940ea339d46SChuck Lever unsigned int i; 94114aeb211SChuck Lever int error = 0; 9421da177e4SLinus Torvalds 9430af39507SWeston Andros Adamson WARN_ON_ONCE(proto == 0 && port == 0); 9440af39507SWeston Andros Adamson if (proto == 0 && port == 0) 9450af39507SWeston Andros Adamson return -EINVAL; 9461da177e4SLinus Torvalds 947bc5fea42SOlaf Kirch for (progp = serv->sv_program; progp; progp = progp->pg_next) { 9481da177e4SLinus Torvalds for (i = 0; i < progp->pg_nvers; i++) { 9497e55b59bSKinglong Mee vers = progp->pg_vers[i]; 9507e55b59bSKinglong Mee if (vers == NULL) 9511da177e4SLinus Torvalds continue; 952bc5fea42SOlaf Kirch 9532c7eb0b2SChuck Lever dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", 954bc5fea42SOlaf Kirch progp->pg_name, 9552c7eb0b2SChuck Lever i, 956bc5fea42SOlaf Kirch proto == IPPROTO_UDP? "udp" : "tcp", 957bc5fea42SOlaf Kirch port, 9584b62e58cSChuck Lever family, 9597e55b59bSKinglong Mee vers->vs_hidden ? 960bc5fea42SOlaf Kirch " (but not telling portmap)" : ""); 961bc5fea42SOlaf Kirch 9627e55b59bSKinglong Mee if (vers->vs_hidden) 963bc5fea42SOlaf Kirch continue; 964bc5fea42SOlaf Kirch 9655247fab5SStanislav Kinsbursky error = __svc_register(net, progp->pg_name, progp->pg_prog, 966363f724cSChuck Lever i, family, proto, port); 9677e55b59bSKinglong Mee 9687e55b59bSKinglong Mee if (vers->vs_rpcb_optnl) { 9697e55b59bSKinglong Mee error = 0; 9707e55b59bSKinglong Mee continue; 9717e55b59bSKinglong Mee } 9727e55b59bSKinglong Mee 9737e55b59bSKinglong Mee if (error < 0) { 9747e55b59bSKinglong Mee printk(KERN_WARNING "svc: failed to register " 9757e55b59bSKinglong Mee "%sv%u RPC service (errno %d).\n", 9767e55b59bSKinglong Mee progp->pg_name, i, -error); 9771da177e4SLinus Torvalds break; 9781da177e4SLinus Torvalds } 979bc5fea42SOlaf Kirch } 9807e55b59bSKinglong Mee } 9811da177e4SLinus Torvalds 9827252d575SChuck Lever return error; 9837252d575SChuck Lever } 9847252d575SChuck Lever 985d5a8620fSChuck Lever /* 986d5a8620fSChuck Lever * If user space is running rpcbind, it should take the v4 UNSET 987d5a8620fSChuck Lever * and clear everything for this [program, version]. If user space 988d5a8620fSChuck Lever * is running portmap, it will reject the v4 UNSET, but won't have 989d5a8620fSChuck Lever * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient 990d5a8620fSChuck Lever * in this case to clear all existing entries for [program, version]. 991d5a8620fSChuck Lever */ 9925247fab5SStanislav Kinsbursky static void __svc_unregister(struct net *net, const u32 program, const u32 version, 993f6fb3f6fSChuck Lever const char *progname) 994f6fb3f6fSChuck Lever { 995f6fb3f6fSChuck Lever int error; 996f6fb3f6fSChuck Lever 9975247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, NULL, ""); 998d5a8620fSChuck Lever 999d5a8620fSChuck Lever /* 1000d5a8620fSChuck Lever * User space didn't support rpcbind v4, so retry this 1001d5a8620fSChuck Lever * request with the legacy rpcbind v2 protocol. 1002d5a8620fSChuck Lever */ 1003d5a8620fSChuck Lever if (error == -EPROTONOSUPPORT) 10045247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, 0, 0); 1005d5a8620fSChuck Lever 1006f6fb3f6fSChuck Lever dprintk("svc: %s(%sv%u), error %d\n", 1007f6fb3f6fSChuck Lever __func__, progname, version, error); 1008f6fb3f6fSChuck Lever } 1009f6fb3f6fSChuck Lever 10107252d575SChuck Lever /* 1011f6fb3f6fSChuck Lever * All netids, bind addresses and ports registered for [program, version] 1012f6fb3f6fSChuck Lever * are removed from the local rpcbind database (if the service is not 1013f6fb3f6fSChuck Lever * hidden) to make way for a new instance of the service. 10147252d575SChuck Lever * 1015f6fb3f6fSChuck Lever * The result of unregistration is reported via dprintk for those who want 1016f6fb3f6fSChuck Lever * verification of the result, but is otherwise not important. 10177252d575SChuck Lever */ 10185247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net) 10197252d575SChuck Lever { 10207252d575SChuck Lever struct svc_program *progp; 10217252d575SChuck Lever unsigned long flags; 10227252d575SChuck Lever unsigned int i; 10237252d575SChuck Lever 10247252d575SChuck Lever clear_thread_flag(TIF_SIGPENDING); 10257252d575SChuck Lever 10267252d575SChuck Lever for (progp = serv->sv_program; progp; progp = progp->pg_next) { 10277252d575SChuck Lever for (i = 0; i < progp->pg_nvers; i++) { 10287252d575SChuck Lever if (progp->pg_vers[i] == NULL) 10297252d575SChuck Lever continue; 10307252d575SChuck Lever if (progp->pg_vers[i]->vs_hidden) 10317252d575SChuck Lever continue; 10327252d575SChuck Lever 10337402ab19SChuck Lever dprintk("svc: attempting to unregister %sv%u\n", 10347402ab19SChuck Lever progp->pg_name, i); 10355247fab5SStanislav Kinsbursky __svc_unregister(net, progp->pg_prog, i, progp->pg_name); 10367252d575SChuck Lever } 10377252d575SChuck Lever } 10387252d575SChuck Lever 10391da177e4SLinus Torvalds spin_lock_irqsave(¤t->sighand->siglock, flags); 10401da177e4SLinus Torvalds recalc_sigpending(); 10411da177e4SLinus Torvalds spin_unlock_irqrestore(¤t->sighand->siglock, flags); 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds /* 10457032a3ddSJ. Bruce Fields * dprintk the given error with the address of the client that caused it. 1046354ecbb9SDr. David Alan Gilbert */ 1047f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 1048b9075fa9SJoe Perches static __printf(2, 3) 1049e87cc472SJoe Perches void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) 1050354ecbb9SDr. David Alan Gilbert { 1051e87cc472SJoe Perches struct va_format vaf; 1052354ecbb9SDr. David Alan Gilbert va_list args; 1053354ecbb9SDr. David Alan Gilbert char buf[RPC_MAX_ADDRBUFLEN]; 1054354ecbb9SDr. David Alan Gilbert 1055354ecbb9SDr. David Alan Gilbert va_start(args, fmt); 1056354ecbb9SDr. David Alan Gilbert 1057e87cc472SJoe Perches vaf.fmt = fmt; 1058e87cc472SJoe Perches vaf.va = &args; 1059e87cc472SJoe Perches 10607032a3ddSJ. Bruce Fields dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); 1061e87cc472SJoe Perches 1062e87cc472SJoe Perches va_end(args); 1063354ecbb9SDr. David Alan Gilbert } 1064624ab464SJ. Bruce Fields #else 1065624ab464SJ. Bruce Fields static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} 1066624ab464SJ. Bruce Fields #endif 1067354ecbb9SDr. David Alan Gilbert 1068354ecbb9SDr. David Alan Gilbert /* 10691cad7ea6SRicardo Labiaga * Common routine for processing the RPC request. 10701da177e4SLinus Torvalds */ 10711cad7ea6SRicardo Labiaga static int 10721cad7ea6SRicardo Labiaga svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) 10731da177e4SLinus Torvalds { 10741da177e4SLinus Torvalds struct svc_program *progp; 10751da177e4SLinus Torvalds struct svc_version *versp = NULL; /* compiler food */ 10761da177e4SLinus Torvalds struct svc_procedure *procp = NULL; 10776fb2b47fSNeilBrown struct svc_serv *serv = rqstp->rq_server; 10781da177e4SLinus Torvalds kxdrproc_t xdr; 1079d8ed029dSAlexey Dobriyan __be32 *statp; 10801cad7ea6SRicardo Labiaga u32 prog, vers, proc; 1081d8ed029dSAlexey Dobriyan __be32 auth_stat, rpc_stat; 10821da177e4SLinus Torvalds int auth_res; 10838f8e05c5SJ.Bruce Fields __be32 *reply_statp; 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds rpc_stat = rpc_success; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds if (argv->iov_len < 6*4) 10881da177e4SLinus Torvalds goto err_short_len; 10891da177e4SLinus Torvalds 10905c04c46aSJ. Bruce Fields /* Will be turned off only in gss privacy case: */ 1091779fb0f3SJeff Layton set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); 10922f425878SAndy Adamson /* Will be turned off only when NFSv4 Sessions are used */ 109330660e04SJeff Layton set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); 109478b65eb3SJeff Layton clear_bit(RQ_DROPME, &rqstp->rq_flags); 1095e831fe65STom Tucker 1096e831fe65STom Tucker /* Setup reply header */ 1097e831fe65STom Tucker rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); 10981da177e4SLinus Torvalds 10991da177e4SLinus Torvalds svc_putu32(resv, rqstp->rq_xid); 11001da177e4SLinus Torvalds 110176994313SAlexey Dobriyan vers = svc_getnl(argv); 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds /* First words of reply: */ 110476994313SAlexey Dobriyan svc_putnl(resv, 1); /* REPLY */ 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds if (vers != 2) /* RPC version number */ 11071da177e4SLinus Torvalds goto err_bad_rpc; 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds /* Save position in case we later decide to reject: */ 11108f8e05c5SJ.Bruce Fields reply_statp = resv->iov_base + resv->iov_len; 11111da177e4SLinus Torvalds 111276994313SAlexey Dobriyan svc_putnl(resv, 0); /* ACCEPT */ 11131da177e4SLinus Torvalds 111476994313SAlexey Dobriyan rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ 111576994313SAlexey Dobriyan rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ 111676994313SAlexey Dobriyan rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ 11171da177e4SLinus Torvalds 111880d188a6SNeilBrown for (progp = serv->sv_program; progp; progp = progp->pg_next) 111980d188a6SNeilBrown if (prog == progp->pg_prog) 112080d188a6SNeilBrown break; 112180d188a6SNeilBrown 11221da177e4SLinus Torvalds /* 11231da177e4SLinus Torvalds * Decode auth data, and add verifier to reply buffer. 11241da177e4SLinus Torvalds * We do this before anything else in order to get a decent 11251da177e4SLinus Torvalds * auth verifier. 11261da177e4SLinus Torvalds */ 11271da177e4SLinus Torvalds auth_res = svc_authenticate(rqstp, &auth_stat); 11281da177e4SLinus Torvalds /* Also give the program a chance to reject this call: */ 112980d188a6SNeilBrown if (auth_res == SVC_OK && progp) { 11301da177e4SLinus Torvalds auth_stat = rpc_autherr_badcred; 11311da177e4SLinus Torvalds auth_res = progp->pg_authenticate(rqstp); 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds switch (auth_res) { 11341da177e4SLinus Torvalds case SVC_OK: 11351da177e4SLinus Torvalds break; 11361da177e4SLinus Torvalds case SVC_GARBAGE: 1137dd35210eSHarshula Jayasuriya goto err_garbage; 11381da177e4SLinus Torvalds case SVC_SYSERR: 11391da177e4SLinus Torvalds rpc_stat = rpc_system_err; 11401da177e4SLinus Torvalds goto err_bad; 11411da177e4SLinus Torvalds case SVC_DENIED: 11421da177e4SLinus Torvalds goto err_bad_auth; 11431ebede86SNeilBrown case SVC_CLOSE: 11441ebede86SNeilBrown if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) 11451ebede86SNeilBrown svc_close_xprt(rqstp->rq_xprt); 11461da177e4SLinus Torvalds case SVC_DROP: 11471da177e4SLinus Torvalds goto dropit; 11481da177e4SLinus Torvalds case SVC_COMPLETE: 11491da177e4SLinus Torvalds goto sendit; 11501da177e4SLinus Torvalds } 11511da177e4SLinus Torvalds 11529ba02638SAndreas Gruenbacher if (progp == NULL) 11531da177e4SLinus Torvalds goto err_bad_prog; 11541da177e4SLinus Torvalds 11551da177e4SLinus Torvalds if (vers >= progp->pg_nvers || 11561da177e4SLinus Torvalds !(versp = progp->pg_vers[vers])) 11571da177e4SLinus Torvalds goto err_bad_vers; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds procp = versp->vs_proc + proc; 11601da177e4SLinus Torvalds if (proc >= versp->vs_nproc || !procp->pc_func) 11611da177e4SLinus Torvalds goto err_bad_proc; 11621da177e4SLinus Torvalds rqstp->rq_procinfo = procp; 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds /* Syntactic check complete */ 11651da177e4SLinus Torvalds serv->sv_stats->rpccnt++; 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds /* Build the reply header. */ 11681da177e4SLinus Torvalds statp = resv->iov_base +resv->iov_len; 116976994313SAlexey Dobriyan svc_putnl(resv, RPC_SUCCESS); 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds /* Bump per-procedure stats counter */ 11721da177e4SLinus Torvalds procp->pc_count++; 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds /* Initialize storage for argp and resp */ 11751da177e4SLinus Torvalds memset(rqstp->rq_argp, 0, procp->pc_argsize); 11761da177e4SLinus Torvalds memset(rqstp->rq_resp, 0, procp->pc_ressize); 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds /* un-reserve some of the out-queue now that we have a 11791da177e4SLinus Torvalds * better idea of reply size 11801da177e4SLinus Torvalds */ 11811da177e4SLinus Torvalds if (procp->pc_xdrressize) 1182cd123012SJeff Layton svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds /* Call the function that processes the request. */ 11851da177e4SLinus Torvalds if (!versp->vs_dispatch) { 11861da177e4SLinus Torvalds /* Decode arguments */ 11871da177e4SLinus Torvalds xdr = procp->pc_decode; 11881da177e4SLinus Torvalds if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) 11891da177e4SLinus Torvalds goto err_garbage; 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds /* Encode reply */ 119478b65eb3SJeff Layton if (test_bit(RQ_DROPME, &rqstp->rq_flags)) { 1195d343fce1SNeilBrown if (procp->pc_release) 1196d343fce1SNeilBrown procp->pc_release(rqstp, NULL, rqstp->rq_resp); 1197d343fce1SNeilBrown goto dropit; 1198d343fce1SNeilBrown } 1199f64f9e71SJoe Perches if (*statp == rpc_success && 1200f64f9e71SJoe Perches (xdr = procp->pc_encode) && 1201f64f9e71SJoe Perches !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { 12021da177e4SLinus Torvalds dprintk("svc: failed to encode reply\n"); 12031da177e4SLinus Torvalds /* serv->sv_stats->rpcsystemerr++; */ 12041da177e4SLinus Torvalds *statp = rpc_system_err; 12051da177e4SLinus Torvalds } 12061da177e4SLinus Torvalds } else { 12071da177e4SLinus Torvalds dprintk("svc: calling dispatcher\n"); 12081da177e4SLinus Torvalds if (!versp->vs_dispatch(rqstp, statp)) { 12091da177e4SLinus Torvalds /* Release reply info */ 12101da177e4SLinus Torvalds if (procp->pc_release) 12111da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12121da177e4SLinus Torvalds goto dropit; 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds /* Check RPC status result */ 12171da177e4SLinus Torvalds if (*statp != rpc_success) 12181da177e4SLinus Torvalds resv->iov_len = ((void*)statp) - resv->iov_base + 4; 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds /* Release reply info */ 12211da177e4SLinus Torvalds if (procp->pc_release) 12221da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds if (procp->pc_encode == NULL) 12251da177e4SLinus Torvalds goto dropit; 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds sendit: 12281da177e4SLinus Torvalds if (svc_authorise(rqstp)) 12291da177e4SLinus Torvalds goto dropit; 12301cad7ea6SRicardo Labiaga return 1; /* Caller can now send it */ 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds dropit: 12331da177e4SLinus Torvalds svc_authorise(rqstp); /* doesn't hurt to call this twice */ 12341da177e4SLinus Torvalds dprintk("svc: svc_process dropit\n"); 12351da177e4SLinus Torvalds return 0; 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds err_short_len: 1238354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "short len %Zd, dropping request\n", 1239354ecbb9SDr. David Alan Gilbert argv->iov_len); 124034e9a63bSNeilBrown 12411da177e4SLinus Torvalds goto dropit; /* drop request */ 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds err_bad_rpc: 12441da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 124576994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 124676994313SAlexey Dobriyan svc_putnl(resv, 0); /* RPC_MISMATCH */ 124776994313SAlexey Dobriyan svc_putnl(resv, 2); /* Only RPCv2 supported */ 124876994313SAlexey Dobriyan svc_putnl(resv, 2); 12491da177e4SLinus Torvalds goto sendit; 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds err_bad_auth: 12521da177e4SLinus Torvalds dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); 12531da177e4SLinus Torvalds serv->sv_stats->rpcbadauth++; 12541da177e4SLinus Torvalds /* Restore write pointer to location of accept status: */ 12558f8e05c5SJ.Bruce Fields xdr_ressize_check(rqstp, reply_statp); 125676994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 125776994313SAlexey Dobriyan svc_putnl(resv, 1); /* AUTH_ERROR */ 125876994313SAlexey Dobriyan svc_putnl(resv, ntohl(auth_stat)); /* status */ 12591da177e4SLinus Torvalds goto sendit; 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds err_bad_prog: 12629ba02638SAndreas Gruenbacher dprintk("svc: unknown program %d\n", prog); 12631da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 126476994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_UNAVAIL); 12651da177e4SLinus Torvalds goto sendit; 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds err_bad_vers: 1268354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", 12691a8eff6dSNeilBrown vers, prog, progp->pg_name); 127034e9a63bSNeilBrown 12711da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 127276994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_MISMATCH); 127376994313SAlexey Dobriyan svc_putnl(resv, progp->pg_lovers); 127476994313SAlexey Dobriyan svc_putnl(resv, progp->pg_hivers); 12751da177e4SLinus Torvalds goto sendit; 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds err_bad_proc: 1278354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown procedure (%d)\n", proc); 127934e9a63bSNeilBrown 12801da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 128176994313SAlexey Dobriyan svc_putnl(resv, RPC_PROC_UNAVAIL); 12821da177e4SLinus Torvalds goto sendit; 12831da177e4SLinus Torvalds 12841da177e4SLinus Torvalds err_garbage: 1285354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "failed to decode args\n"); 128634e9a63bSNeilBrown 12871da177e4SLinus Torvalds rpc_stat = rpc_garbage_args; 12881da177e4SLinus Torvalds err_bad: 12891da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 129076994313SAlexey Dobriyan svc_putnl(resv, ntohl(rpc_stat)); 12911da177e4SLinus Torvalds goto sendit; 12921da177e4SLinus Torvalds } 129324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_process); 12947adae489SGreg Banks 12957adae489SGreg Banks /* 12961cad7ea6SRicardo Labiaga * Process the RPC request. 12971cad7ea6SRicardo Labiaga */ 12981cad7ea6SRicardo Labiaga int 12991cad7ea6SRicardo Labiaga svc_process(struct svc_rqst *rqstp) 13001cad7ea6SRicardo Labiaga { 13011cad7ea6SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 13021cad7ea6SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 13031cad7ea6SRicardo Labiaga struct svc_serv *serv = rqstp->rq_server; 13041cad7ea6SRicardo Labiaga u32 dir; 13051cad7ea6SRicardo Labiaga 13061cad7ea6SRicardo Labiaga /* 13071cad7ea6SRicardo Labiaga * Setup response xdr_buf. 13081cad7ea6SRicardo Labiaga * Initially it has just one page 13091cad7ea6SRicardo Labiaga */ 1310afc59400SJ. Bruce Fields rqstp->rq_next_page = &rqstp->rq_respages[1]; 13111cad7ea6SRicardo Labiaga resv->iov_base = page_address(rqstp->rq_respages[0]); 13121cad7ea6SRicardo Labiaga resv->iov_len = 0; 13131cad7ea6SRicardo Labiaga rqstp->rq_res.pages = rqstp->rq_respages + 1; 13141cad7ea6SRicardo Labiaga rqstp->rq_res.len = 0; 13151cad7ea6SRicardo Labiaga rqstp->rq_res.page_base = 0; 13161cad7ea6SRicardo Labiaga rqstp->rq_res.page_len = 0; 13171cad7ea6SRicardo Labiaga rqstp->rq_res.buflen = PAGE_SIZE; 13181cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_base = NULL; 13191cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_len = 0; 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++; 1326860a0d9eSJeff Layton goto out_drop; 13271cad7ea6SRicardo Labiaga } 13281cad7ea6SRicardo Labiaga 13294b5b3ba1SAndy Adamson /* Returns 1 for send, 0 for drop */ 1330860a0d9eSJeff Layton if (likely(svc_process_common(rqstp, argv, resv))) { 1331860a0d9eSJeff Layton int ret = svc_send(rqstp); 1332860a0d9eSJeff Layton 1333860a0d9eSJeff Layton trace_svc_process(rqstp, ret); 1334860a0d9eSJeff Layton return ret; 1335860a0d9eSJeff Layton } 1336860a0d9eSJeff Layton out_drop: 1337860a0d9eSJeff Layton trace_svc_process(rqstp, 0); 13384b5b3ba1SAndy Adamson svc_drop(rqstp); 13394b5b3ba1SAndy Adamson return 0; 13404b5b3ba1SAndy Adamson } 13411cad7ea6SRicardo Labiaga 13429e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL) 13434d6bbb62SRicardo Labiaga /* 13444d6bbb62SRicardo Labiaga * Process a backchannel RPC request that arrived over an existing 13454d6bbb62SRicardo Labiaga * outbound connection 13464d6bbb62SRicardo Labiaga */ 13474d6bbb62SRicardo Labiaga int 13484d6bbb62SRicardo Labiaga bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, 13494d6bbb62SRicardo Labiaga struct svc_rqst *rqstp) 13504d6bbb62SRicardo Labiaga { 13514d6bbb62SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 13524d6bbb62SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 1353632dda83SChuck Lever struct rpc_task *task; 1354*0d2a970dSTrond Myklebust int proc_error; 1355632dda83SChuck Lever int error; 1356632dda83SChuck Lever 1357632dda83SChuck Lever dprintk("svc: %s(%p)\n", __func__, req); 13584d6bbb62SRicardo Labiaga 13594d6bbb62SRicardo Labiaga /* Build the svc_rqst used by the common processing routine */ 13604a19de0fSAndy Adamson rqstp->rq_xprt = serv->sv_bc_xprt; 13614d6bbb62SRicardo Labiaga rqstp->rq_xid = req->rq_xid; 13624d6bbb62SRicardo Labiaga rqstp->rq_prot = req->rq_xprt->prot; 13634d6bbb62SRicardo Labiaga rqstp->rq_server = serv; 13644d6bbb62SRicardo Labiaga 13654d6bbb62SRicardo Labiaga rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); 13664d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); 13674d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); 13684d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); 13694d6bbb62SRicardo Labiaga 13704d6bbb62SRicardo Labiaga /* reset result send buffer "put" position */ 13714d6bbb62SRicardo Labiaga resv->iov_len = 0; 13724d6bbb62SRicardo Labiaga 13734d6bbb62SRicardo Labiaga if (rqstp->rq_prot != IPPROTO_TCP) { 13744d6bbb62SRicardo Labiaga printk(KERN_ERR "No support for Non-TCP transports!\n"); 13754d6bbb62SRicardo Labiaga BUG(); 13764d6bbb62SRicardo Labiaga } 13774d6bbb62SRicardo Labiaga 13784d6bbb62SRicardo Labiaga /* 13794d6bbb62SRicardo Labiaga * Skip the next two words because they've already been 1380632dda83SChuck Lever * processed in the transport 13814d6bbb62SRicardo Labiaga */ 13824d6bbb62SRicardo Labiaga svc_getu32(argv); /* XID */ 13834d6bbb62SRicardo Labiaga svc_getnl(argv); /* CALLDIR */ 13844d6bbb62SRicardo Labiaga 1385632dda83SChuck Lever /* Parse and execute the bc call */ 1386*0d2a970dSTrond Myklebust proc_error = svc_process_common(rqstp, argv, resv); 1387*0d2a970dSTrond Myklebust 1388*0d2a970dSTrond Myklebust atomic_inc(&req->rq_xprt->bc_free_slots); 1389*0d2a970dSTrond Myklebust if (!proc_error) { 1390632dda83SChuck Lever /* Processing error: drop the request */ 1391b3b02ae5STrond Myklebust xprt_free_bc_request(req); 13924b5b3ba1SAndy Adamson return 0; 13934b5b3ba1SAndy Adamson } 1394632dda83SChuck Lever 1395632dda83SChuck Lever /* Finally, send the reply synchronously */ 1396632dda83SChuck Lever memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); 13970f419791STrond Myklebust task = rpc_run_bc_task(req); 1398632dda83SChuck Lever if (IS_ERR(task)) { 1399632dda83SChuck Lever error = PTR_ERR(task); 1400632dda83SChuck Lever goto out; 1401632dda83SChuck Lever } 1402632dda83SChuck Lever 1403632dda83SChuck Lever WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); 1404632dda83SChuck Lever error = task->tk_status; 1405632dda83SChuck Lever rpc_put_task(task); 1406632dda83SChuck Lever 1407632dda83SChuck Lever out: 1408632dda83SChuck Lever dprintk("svc: %s(), error=%d\n", __func__, error); 1409632dda83SChuck Lever return error; 14104d6bbb62SRicardo Labiaga } 14110d961aa9STrond Myklebust EXPORT_SYMBOL_GPL(bc_svc_process); 14129e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */ 14134d6bbb62SRicardo Labiaga 14141cad7ea6SRicardo Labiaga /* 14157adae489SGreg Banks * Return (transport-specific) limit on the rpc payload. 14167adae489SGreg Banks */ 14177adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp) 14187adae489SGreg Banks { 141949023155STom Tucker u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload; 14207adae489SGreg Banks 1421c6b0a9f8SNeilBrown if (rqstp->rq_server->sv_max_payload < max) 1422c6b0a9f8SNeilBrown max = rqstp->rq_server->sv_max_payload; 14237adae489SGreg Banks return max; 14247adae489SGreg Banks } 14257adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload); 1426