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 37c369014fSJeff Layton #define svc_serv_is_pooled(serv) ((serv)->sv_ops->svo_function) 3842a7fc4aSGreg Banks 3942a7fc4aSGreg Banks #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL 40bfd24160SGreg Banks 41bfd24160SGreg Banks /* 42bfd24160SGreg Banks * Structure for mapping cpus to pools and vice versa. 43bfd24160SGreg Banks * Setup once during sunrpc initialisation. 44bfd24160SGreg Banks */ 45d70bc0c6SJeff Layton struct svc_pool_map svc_pool_map = { 4642a7fc4aSGreg Banks .mode = SVC_POOL_DEFAULT 47bfd24160SGreg Banks }; 48d70bc0c6SJeff Layton EXPORT_SYMBOL_GPL(svc_pool_map); 49d70bc0c6SJeff Layton 5042a7fc4aSGreg Banks static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ 51bfd24160SGreg Banks 5242a7fc4aSGreg Banks static int 5342a7fc4aSGreg Banks param_set_pool_mode(const char *val, struct kernel_param *kp) 5442a7fc4aSGreg Banks { 5542a7fc4aSGreg Banks int *ip = (int *)kp->arg; 5642a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 5742a7fc4aSGreg Banks int err; 5842a7fc4aSGreg Banks 5942a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 6042a7fc4aSGreg Banks 6142a7fc4aSGreg Banks err = -EBUSY; 6242a7fc4aSGreg Banks if (m->count) 6342a7fc4aSGreg Banks goto out; 6442a7fc4aSGreg Banks 6542a7fc4aSGreg Banks err = 0; 6642a7fc4aSGreg Banks if (!strncmp(val, "auto", 4)) 6742a7fc4aSGreg Banks *ip = SVC_POOL_AUTO; 6842a7fc4aSGreg Banks else if (!strncmp(val, "global", 6)) 6942a7fc4aSGreg Banks *ip = SVC_POOL_GLOBAL; 7042a7fc4aSGreg Banks else if (!strncmp(val, "percpu", 6)) 7142a7fc4aSGreg Banks *ip = SVC_POOL_PERCPU; 7242a7fc4aSGreg Banks else if (!strncmp(val, "pernode", 7)) 7342a7fc4aSGreg Banks *ip = SVC_POOL_PERNODE; 7442a7fc4aSGreg Banks else 7542a7fc4aSGreg Banks err = -EINVAL; 7642a7fc4aSGreg Banks 7742a7fc4aSGreg Banks out: 7842a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 7942a7fc4aSGreg Banks return err; 8042a7fc4aSGreg Banks } 8142a7fc4aSGreg Banks 8242a7fc4aSGreg Banks static int 8342a7fc4aSGreg Banks param_get_pool_mode(char *buf, struct kernel_param *kp) 8442a7fc4aSGreg Banks { 8542a7fc4aSGreg Banks int *ip = (int *)kp->arg; 8642a7fc4aSGreg Banks 8742a7fc4aSGreg Banks switch (*ip) 8842a7fc4aSGreg Banks { 8942a7fc4aSGreg Banks case SVC_POOL_AUTO: 9042a7fc4aSGreg Banks return strlcpy(buf, "auto", 20); 9142a7fc4aSGreg Banks case SVC_POOL_GLOBAL: 9242a7fc4aSGreg Banks return strlcpy(buf, "global", 20); 9342a7fc4aSGreg Banks case SVC_POOL_PERCPU: 9442a7fc4aSGreg Banks return strlcpy(buf, "percpu", 20); 9542a7fc4aSGreg Banks case SVC_POOL_PERNODE: 9642a7fc4aSGreg Banks return strlcpy(buf, "pernode", 20); 9742a7fc4aSGreg Banks default: 9842a7fc4aSGreg Banks return sprintf(buf, "%d", *ip); 9942a7fc4aSGreg Banks } 10042a7fc4aSGreg Banks } 10142a7fc4aSGreg Banks 10242a7fc4aSGreg Banks module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode, 10342a7fc4aSGreg Banks &svc_pool_map.mode, 0644); 104bfd24160SGreg Banks 105bfd24160SGreg Banks /* 106bfd24160SGreg Banks * Detect best pool mapping mode heuristically, 107bfd24160SGreg Banks * according to the machine's topology. 108bfd24160SGreg Banks */ 109bfd24160SGreg Banks static int 110bfd24160SGreg Banks svc_pool_map_choose_mode(void) 111bfd24160SGreg Banks { 112bfd24160SGreg Banks unsigned int node; 113bfd24160SGreg Banks 11462bc62a8SChristoph Lameter if (nr_online_nodes > 1) { 115bfd24160SGreg Banks /* 116bfd24160SGreg Banks * Actually have multiple NUMA nodes, 117bfd24160SGreg Banks * so split pools on NUMA node boundaries 118bfd24160SGreg Banks */ 119bfd24160SGreg Banks return SVC_POOL_PERNODE; 120bfd24160SGreg Banks } 121bfd24160SGreg Banks 12272c33688SH Hartley Sweeten node = first_online_node; 123bfd24160SGreg Banks if (nr_cpus_node(node) > 2) { 124bfd24160SGreg Banks /* 125bfd24160SGreg Banks * Non-trivial SMP, or CONFIG_NUMA on 126bfd24160SGreg Banks * non-NUMA hardware, e.g. with a generic 127bfd24160SGreg Banks * x86_64 kernel on Xeons. In this case we 128bfd24160SGreg Banks * want to divide the pools on cpu boundaries. 129bfd24160SGreg Banks */ 130bfd24160SGreg Banks return SVC_POOL_PERCPU; 131bfd24160SGreg Banks } 132bfd24160SGreg Banks 133bfd24160SGreg Banks /* default: one global pool */ 134bfd24160SGreg Banks return SVC_POOL_GLOBAL; 135bfd24160SGreg Banks } 136bfd24160SGreg Banks 137bfd24160SGreg Banks /* 138bfd24160SGreg Banks * Allocate the to_pool[] and pool_to[] arrays. 139bfd24160SGreg Banks * Returns 0 on success or an errno. 140bfd24160SGreg Banks */ 141bfd24160SGreg Banks static int 142bfd24160SGreg Banks svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) 143bfd24160SGreg Banks { 144bfd24160SGreg Banks m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 145bfd24160SGreg Banks if (!m->to_pool) 146bfd24160SGreg Banks goto fail; 147bfd24160SGreg Banks m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 148bfd24160SGreg Banks if (!m->pool_to) 149bfd24160SGreg Banks goto fail_free; 150bfd24160SGreg Banks 151bfd24160SGreg Banks return 0; 152bfd24160SGreg Banks 153bfd24160SGreg Banks fail_free: 154bfd24160SGreg Banks kfree(m->to_pool); 15561c8504cSJ. Bruce Fields m->to_pool = NULL; 156bfd24160SGreg Banks fail: 157bfd24160SGreg Banks return -ENOMEM; 158bfd24160SGreg Banks } 159bfd24160SGreg Banks 160bfd24160SGreg Banks /* 161bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERCPU mode. 162bfd24160SGreg Banks * Returns number of pools or <0 on error. 163bfd24160SGreg Banks */ 164bfd24160SGreg Banks static int 165bfd24160SGreg Banks svc_pool_map_init_percpu(struct svc_pool_map *m) 166bfd24160SGreg Banks { 16753b8a315SChristoph Lameter unsigned int maxpools = nr_cpu_ids; 168bfd24160SGreg Banks unsigned int pidx = 0; 169bfd24160SGreg Banks unsigned int cpu; 170bfd24160SGreg Banks int err; 171bfd24160SGreg Banks 172bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 173bfd24160SGreg Banks if (err) 174bfd24160SGreg Banks return err; 175bfd24160SGreg Banks 176bfd24160SGreg Banks for_each_online_cpu(cpu) { 177eb63192bSDan Carpenter BUG_ON(pidx >= maxpools); 178bfd24160SGreg Banks m->to_pool[cpu] = pidx; 179bfd24160SGreg Banks m->pool_to[pidx] = cpu; 180bfd24160SGreg Banks pidx++; 181bfd24160SGreg Banks } 182bfd24160SGreg Banks /* cpus brought online later all get mapped to pool0, sorry */ 183bfd24160SGreg Banks 184bfd24160SGreg Banks return pidx; 185bfd24160SGreg Banks }; 186bfd24160SGreg Banks 187bfd24160SGreg Banks 188bfd24160SGreg Banks /* 189bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERNODE mode. 190bfd24160SGreg Banks * Returns number of pools or <0 on error. 191bfd24160SGreg Banks */ 192bfd24160SGreg Banks static int 193bfd24160SGreg Banks svc_pool_map_init_pernode(struct svc_pool_map *m) 194bfd24160SGreg Banks { 19574c7aa8bSChristoph Lameter unsigned int maxpools = nr_node_ids; 196bfd24160SGreg Banks unsigned int pidx = 0; 197bfd24160SGreg Banks unsigned int node; 198bfd24160SGreg Banks int err; 199bfd24160SGreg Banks 200bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 201bfd24160SGreg Banks if (err) 202bfd24160SGreg Banks return err; 203bfd24160SGreg Banks 204bfd24160SGreg Banks for_each_node_with_cpus(node) { 205bfd24160SGreg Banks /* some architectures (e.g. SN2) have cpuless nodes */ 206bfd24160SGreg Banks BUG_ON(pidx > maxpools); 207bfd24160SGreg Banks m->to_pool[node] = pidx; 208bfd24160SGreg Banks m->pool_to[pidx] = node; 209bfd24160SGreg Banks pidx++; 210bfd24160SGreg Banks } 211bfd24160SGreg Banks /* nodes brought online later all get mapped to pool0, sorry */ 212bfd24160SGreg Banks 213bfd24160SGreg Banks return pidx; 214bfd24160SGreg Banks } 215bfd24160SGreg Banks 216bfd24160SGreg Banks 217bfd24160SGreg Banks /* 21842a7fc4aSGreg Banks * Add a reference to the global map of cpus to pools (and 21942a7fc4aSGreg Banks * vice versa). Initialise the map if we're the first user. 22042a7fc4aSGreg Banks * Returns the number of pools. 221bfd24160SGreg Banks */ 222d70bc0c6SJeff Layton unsigned int 22342a7fc4aSGreg Banks svc_pool_map_get(void) 224bfd24160SGreg Banks { 225bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 226bfd24160SGreg Banks int npools = -1; 227bfd24160SGreg Banks 22842a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 229bfd24160SGreg Banks 23042a7fc4aSGreg Banks if (m->count++) { 23142a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 23242a7fc4aSGreg Banks return m->npools; 23342a7fc4aSGreg Banks } 23442a7fc4aSGreg Banks 23542a7fc4aSGreg Banks if (m->mode == SVC_POOL_AUTO) 236bfd24160SGreg Banks m->mode = svc_pool_map_choose_mode(); 237bfd24160SGreg Banks 238bfd24160SGreg Banks switch (m->mode) { 239bfd24160SGreg Banks case SVC_POOL_PERCPU: 240bfd24160SGreg Banks npools = svc_pool_map_init_percpu(m); 241bfd24160SGreg Banks break; 242bfd24160SGreg Banks case SVC_POOL_PERNODE: 243bfd24160SGreg Banks npools = svc_pool_map_init_pernode(m); 244bfd24160SGreg Banks break; 245bfd24160SGreg Banks } 246bfd24160SGreg Banks 247bfd24160SGreg Banks if (npools < 0) { 248bfd24160SGreg Banks /* default, or memory allocation failure */ 249bfd24160SGreg Banks npools = 1; 250bfd24160SGreg Banks m->mode = SVC_POOL_GLOBAL; 251bfd24160SGreg Banks } 252bfd24160SGreg Banks m->npools = npools; 253bfd24160SGreg Banks 25442a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 255bfd24160SGreg Banks return m->npools; 256bfd24160SGreg Banks } 257d70bc0c6SJeff Layton EXPORT_SYMBOL_GPL(svc_pool_map_get); 25842a7fc4aSGreg Banks 25942a7fc4aSGreg Banks /* 26042a7fc4aSGreg Banks * Drop a reference to the global map of cpus to pools. 26142a7fc4aSGreg Banks * When the last reference is dropped, the map data is 26242a7fc4aSGreg Banks * freed; this allows the sysadmin to change the pool 26342a7fc4aSGreg Banks * mode using the pool_mode module option without 26442a7fc4aSGreg Banks * rebooting or re-loading sunrpc.ko. 26542a7fc4aSGreg Banks */ 266d70bc0c6SJeff Layton void 26742a7fc4aSGreg Banks svc_pool_map_put(void) 26842a7fc4aSGreg Banks { 26942a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 27042a7fc4aSGreg Banks 27142a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 27242a7fc4aSGreg Banks 27342a7fc4aSGreg Banks if (!--m->count) { 27442a7fc4aSGreg Banks kfree(m->to_pool); 27561c8504cSJ. Bruce Fields m->to_pool = NULL; 27642a7fc4aSGreg Banks kfree(m->pool_to); 27761c8504cSJ. Bruce Fields m->pool_to = NULL; 27842a7fc4aSGreg Banks m->npools = 0; 27942a7fc4aSGreg Banks } 28042a7fc4aSGreg Banks 28142a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 28242a7fc4aSGreg Banks } 283d70bc0c6SJeff Layton EXPORT_SYMBOL_GPL(svc_pool_map_put); 28442a7fc4aSGreg Banks 28511fd165cSEric Dumazet static int svc_pool_map_get_node(unsigned int pidx) 28611fd165cSEric Dumazet { 28711fd165cSEric Dumazet const struct svc_pool_map *m = &svc_pool_map; 28811fd165cSEric Dumazet 28911fd165cSEric Dumazet if (m->count) { 29011fd165cSEric Dumazet if (m->mode == SVC_POOL_PERCPU) 29111fd165cSEric Dumazet return cpu_to_node(m->pool_to[pidx]); 29211fd165cSEric Dumazet if (m->mode == SVC_POOL_PERNODE) 29311fd165cSEric Dumazet return m->pool_to[pidx]; 29411fd165cSEric Dumazet } 29511fd165cSEric Dumazet return NUMA_NO_NODE; 29611fd165cSEric Dumazet } 297bfd24160SGreg Banks /* 2989867d76cSJeff Layton * Set the given thread's cpus_allowed mask so that it 299bfd24160SGreg Banks * will only run on cpus in the given pool. 300bfd24160SGreg Banks */ 3019867d76cSJeff Layton static inline void 3029867d76cSJeff Layton svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) 303bfd24160SGreg Banks { 304bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 3059867d76cSJeff Layton unsigned int node = m->pool_to[pidx]; 306bfd24160SGreg Banks 307bfd24160SGreg Banks /* 308bfd24160SGreg Banks * The caller checks for sv_nrpools > 1, which 30942a7fc4aSGreg Banks * implies that we've been initialized. 310bfd24160SGreg Banks */ 3111bd58aafSWeston Andros Adamson WARN_ON_ONCE(m->count == 0); 3121bd58aafSWeston Andros Adamson if (m->count == 0) 3131bd58aafSWeston Andros Adamson return; 314bfd24160SGreg Banks 3159867d76cSJeff Layton switch (m->mode) { 316bfd24160SGreg Banks case SVC_POOL_PERCPU: 317c5f59f08SMike Travis { 318aa85ea5bSRusty Russell set_cpus_allowed_ptr(task, cpumask_of(node)); 3199867d76cSJeff Layton break; 320c5f59f08SMike Travis } 321bfd24160SGreg Banks case SVC_POOL_PERNODE: 322c5f59f08SMike Travis { 323a70f7302SRusty Russell set_cpus_allowed_ptr(task, cpumask_of_node(node)); 3249867d76cSJeff Layton break; 325bfd24160SGreg Banks } 326bfd24160SGreg Banks } 327c5f59f08SMike Travis } 328bfd24160SGreg Banks 329bfd24160SGreg Banks /* 330bfd24160SGreg Banks * Use the mapping mode to choose a pool for a given CPU. 331bfd24160SGreg Banks * Used when enqueueing an incoming RPC. Always returns 332bfd24160SGreg Banks * a non-NULL pool pointer. 333bfd24160SGreg Banks */ 334bfd24160SGreg Banks struct svc_pool * 335bfd24160SGreg Banks svc_pool_for_cpu(struct svc_serv *serv, int cpu) 336bfd24160SGreg Banks { 337bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 338bfd24160SGreg Banks unsigned int pidx = 0; 339bfd24160SGreg Banks 340bfd24160SGreg Banks /* 34142a7fc4aSGreg Banks * An uninitialised map happens in a pure client when 342bfd24160SGreg Banks * lockd is brought up, so silently treat it the 343bfd24160SGreg Banks * same as SVC_POOL_GLOBAL. 344bfd24160SGreg Banks */ 34542a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) { 346bfd24160SGreg Banks switch (m->mode) { 347bfd24160SGreg Banks case SVC_POOL_PERCPU: 348bfd24160SGreg Banks pidx = m->to_pool[cpu]; 349bfd24160SGreg Banks break; 350bfd24160SGreg Banks case SVC_POOL_PERNODE: 351bfd24160SGreg Banks pidx = m->to_pool[cpu_to_node(cpu)]; 352bfd24160SGreg Banks break; 353bfd24160SGreg Banks } 35442a7fc4aSGreg Banks } 355bfd24160SGreg Banks return &serv->sv_pools[pidx % serv->sv_nrpools]; 356bfd24160SGreg Banks } 357bfd24160SGreg Banks 358bb2224dfSStanislav Kinsbursky int svc_rpcb_setup(struct svc_serv *serv, struct net *net) 359d9908560SStanislav Kinsbursky { 360d9908560SStanislav Kinsbursky int err; 361d9908560SStanislav Kinsbursky 362bee42f68SStanislav Kinsbursky err = rpcb_create_local(net); 363d9908560SStanislav Kinsbursky if (err) 364d9908560SStanislav Kinsbursky return err; 365d9908560SStanislav Kinsbursky 366d9908560SStanislav Kinsbursky /* Remove any stale portmap registrations */ 367bee42f68SStanislav Kinsbursky svc_unregister(serv, net); 368d9908560SStanislav Kinsbursky return 0; 369d9908560SStanislav Kinsbursky } 370bb2224dfSStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_setup); 371d9908560SStanislav Kinsbursky 3725ecebb7cSStanislav Kinsbursky void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) 373d9908560SStanislav Kinsbursky { 3745ecebb7cSStanislav Kinsbursky svc_unregister(serv, net); 3755ecebb7cSStanislav Kinsbursky rpcb_put_local(net); 376d9908560SStanislav Kinsbursky } 37716d05870SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); 378d9908560SStanislav Kinsbursky 379d9908560SStanislav Kinsbursky static int svc_uses_rpcbind(struct svc_serv *serv) 380d9908560SStanislav Kinsbursky { 381d9908560SStanislav Kinsbursky struct svc_program *progp; 382d9908560SStanislav Kinsbursky unsigned int i; 383d9908560SStanislav Kinsbursky 384d9908560SStanislav Kinsbursky for (progp = serv->sv_program; progp; progp = progp->pg_next) { 385d9908560SStanislav Kinsbursky for (i = 0; i < progp->pg_nvers; i++) { 386d9908560SStanislav Kinsbursky if (progp->pg_vers[i] == NULL) 387d9908560SStanislav Kinsbursky continue; 388d9908560SStanislav Kinsbursky if (progp->pg_vers[i]->vs_hidden == 0) 389d9908560SStanislav Kinsbursky return 1; 390d9908560SStanislav Kinsbursky } 391d9908560SStanislav Kinsbursky } 392d9908560SStanislav Kinsbursky 393d9908560SStanislav Kinsbursky return 0; 394d9908560SStanislav Kinsbursky } 395bfd24160SGreg Banks 3969793f7c8SStanislav Kinsbursky int svc_bind(struct svc_serv *serv, struct net *net) 3979793f7c8SStanislav Kinsbursky { 3989793f7c8SStanislav Kinsbursky if (!svc_uses_rpcbind(serv)) 3999793f7c8SStanislav Kinsbursky return 0; 4009793f7c8SStanislav Kinsbursky return svc_rpcb_setup(serv, net); 4019793f7c8SStanislav Kinsbursky } 4029793f7c8SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_bind); 4039793f7c8SStanislav Kinsbursky 404bfd24160SGreg Banks /* 4051da177e4SLinus Torvalds * Create an RPC service 4061da177e4SLinus Torvalds */ 407a7455442SGreg Banks static struct svc_serv * 408a7455442SGreg Banks __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, 409ea126e74SJeff Layton struct svc_serv_ops *ops) 4101da177e4SLinus Torvalds { 4111da177e4SLinus Torvalds struct svc_serv *serv; 412ea339d46SChuck Lever unsigned int vers; 4131da177e4SLinus Torvalds unsigned int xdrsize; 4143262c816SGreg Banks unsigned int i; 4151da177e4SLinus Torvalds 4160da974f4SPanagiotis Issaris if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) 4171da177e4SLinus Torvalds return NULL; 4189ba02638SAndreas Gruenbacher serv->sv_name = prog->pg_name; 4191da177e4SLinus Torvalds serv->sv_program = prog; 4201da177e4SLinus Torvalds serv->sv_nrthreads = 1; 4211da177e4SLinus Torvalds serv->sv_stats = prog->pg_stats; 422c6b0a9f8SNeilBrown if (bufsize > RPCSVC_MAXPAYLOAD) 423c6b0a9f8SNeilBrown bufsize = RPCSVC_MAXPAYLOAD; 424c6b0a9f8SNeilBrown serv->sv_max_payload = bufsize? bufsize : 4096; 425c6b0a9f8SNeilBrown serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); 426ea126e74SJeff Layton serv->sv_ops = ops; 4271da177e4SLinus Torvalds xdrsize = 0; 4289ba02638SAndreas Gruenbacher while (prog) { 4299ba02638SAndreas Gruenbacher prog->pg_lovers = prog->pg_nvers-1; 4301da177e4SLinus Torvalds for (vers=0; vers<prog->pg_nvers ; vers++) 4311da177e4SLinus Torvalds if (prog->pg_vers[vers]) { 4321da177e4SLinus Torvalds prog->pg_hivers = vers; 4331da177e4SLinus Torvalds if (prog->pg_lovers > vers) 4341da177e4SLinus Torvalds prog->pg_lovers = vers; 4351da177e4SLinus Torvalds if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) 4361da177e4SLinus Torvalds xdrsize = prog->pg_vers[vers]->vs_xdrsize; 4371da177e4SLinus Torvalds } 4389ba02638SAndreas Gruenbacher prog = prog->pg_next; 4399ba02638SAndreas Gruenbacher } 4401da177e4SLinus Torvalds serv->sv_xdrsize = xdrsize; 4411da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_tempsocks); 4421da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_permsocks); 44336bdfc8bSGreg Banks init_timer(&serv->sv_temptimer); 4441da177e4SLinus Torvalds spin_lock_init(&serv->sv_lock); 4451da177e4SLinus Torvalds 446a7455442SGreg Banks serv->sv_nrpools = npools; 4473262c816SGreg Banks serv->sv_pools = 448cd861280SRobert P. J. Day kcalloc(serv->sv_nrpools, sizeof(struct svc_pool), 4493262c816SGreg Banks GFP_KERNEL); 4503262c816SGreg Banks if (!serv->sv_pools) { 4513262c816SGreg Banks kfree(serv); 4523262c816SGreg Banks return NULL; 4533262c816SGreg Banks } 4543262c816SGreg Banks 4553262c816SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 4563262c816SGreg Banks struct svc_pool *pool = &serv->sv_pools[i]; 4573262c816SGreg Banks 45846121cf7SChuck Lever dprintk("svc: initialising pool %u for %s\n", 4593262c816SGreg Banks i, serv->sv_name); 4603262c816SGreg Banks 4613262c816SGreg Banks pool->sp_id = i; 4623262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_sockets); 463a7455442SGreg Banks INIT_LIST_HEAD(&pool->sp_all_threads); 4643262c816SGreg Banks spin_lock_init(&pool->sp_lock); 4653262c816SGreg Banks } 4663262c816SGreg Banks 4671da177e4SLinus Torvalds return serv; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 470a7455442SGreg Banks struct svc_serv * 471a7455442SGreg Banks svc_create(struct svc_program *prog, unsigned int bufsize, 472ea126e74SJeff Layton struct svc_serv_ops *ops) 473a7455442SGreg Banks { 474ea126e74SJeff Layton return __svc_create(prog, bufsize, /*npools*/1, ops); 475a7455442SGreg Banks } 47624c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create); 477a7455442SGreg Banks 478a7455442SGreg Banks struct svc_serv * 479a7455442SGreg Banks svc_create_pooled(struct svc_program *prog, unsigned int bufsize, 480758f62ffSJeff Layton struct svc_serv_ops *ops) 481a7455442SGreg Banks { 482a7455442SGreg Banks struct svc_serv *serv; 48342a7fc4aSGreg Banks unsigned int npools = svc_pool_map_get(); 484a7455442SGreg Banks 485ea126e74SJeff Layton serv = __svc_create(prog, bufsize, npools, ops); 486067f96efSJeff Layton if (!serv) 487067f96efSJeff Layton goto out_err; 488a7455442SGreg Banks return serv; 489067f96efSJeff Layton out_err: 490067f96efSJeff Layton svc_pool_map_put(); 491067f96efSJeff Layton return NULL; 492a7455442SGreg Banks } 49324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_create_pooled); 494a7455442SGreg Banks 495074d0f67SStanislav Kinsbursky void svc_shutdown_net(struct svc_serv *serv, struct net *net) 496074d0f67SStanislav Kinsbursky { 497074d0f67SStanislav Kinsbursky svc_close_net(serv, net); 498074d0f67SStanislav Kinsbursky 499ea126e74SJeff Layton if (serv->sv_ops->svo_shutdown) 500ea126e74SJeff Layton serv->sv_ops->svo_shutdown(serv, net); 501074d0f67SStanislav Kinsbursky } 502074d0f67SStanislav Kinsbursky EXPORT_SYMBOL_GPL(svc_shutdown_net); 503074d0f67SStanislav Kinsbursky 5041da177e4SLinus Torvalds /* 505bedbdd8bSNeil Brown * Destroy an RPC service. Should be called with appropriate locking to 506bedbdd8bSNeil Brown * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. 5071da177e4SLinus Torvalds */ 5081da177e4SLinus Torvalds void 5091da177e4SLinus Torvalds svc_destroy(struct svc_serv *serv) 5101da177e4SLinus Torvalds { 51146121cf7SChuck Lever dprintk("svc: svc_destroy(%s, %d)\n", 5121da177e4SLinus Torvalds serv->sv_program->pg_name, 5131da177e4SLinus Torvalds serv->sv_nrthreads); 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds if (serv->sv_nrthreads) { 5161da177e4SLinus Torvalds if (--(serv->sv_nrthreads) != 0) { 5171da177e4SLinus Torvalds svc_sock_update_bufs(serv); 5181da177e4SLinus Torvalds return; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds } else 5211da177e4SLinus Torvalds printk("svc_destroy: no threads for serv=%p!\n", serv); 5221da177e4SLinus Torvalds 52336bdfc8bSGreg Banks del_timer_sync(&serv->sv_temptimer); 524074d0f67SStanislav Kinsbursky 5257b147f1fSStanislav Kinsbursky /* 5267b147f1fSStanislav Kinsbursky * The last user is gone and thus all sockets have to be destroyed to 5277b147f1fSStanislav Kinsbursky * the point. Check this. 5287b147f1fSStanislav Kinsbursky */ 5297b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_permsocks)); 5307b147f1fSStanislav Kinsbursky BUG_ON(!list_empty(&serv->sv_tempsocks)); 531cda1fd4aSNeilBrown 5321da177e4SLinus Torvalds cache_clean_deferred(serv); 5331da177e4SLinus Torvalds 53442a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) 53542a7fc4aSGreg Banks svc_pool_map_put(); 53642a7fc4aSGreg Banks 5373262c816SGreg Banks kfree(serv->sv_pools); 5381da177e4SLinus Torvalds kfree(serv); 5391da177e4SLinus Torvalds } 54024c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_destroy); 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds /* 5431da177e4SLinus Torvalds * Allocate an RPC server's buffer space. 5441da177e4SLinus Torvalds * We allocate pages and place them in rq_argpages. 5451da177e4SLinus Torvalds */ 5461da177e4SLinus Torvalds static int 54711fd165cSEric Dumazet svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node) 5481da177e4SLinus Torvalds { 5490dc220f0SChuck Lever unsigned int pages, arghi; 5501da177e4SLinus Torvalds 551ba17686fSAndy Adamson /* bc_xprt uses fore channel allocated buffers */ 552ba17686fSAndy Adamson if (svc_is_backchannel(rqstp)) 553ba17686fSAndy Adamson return 1; 554ba17686fSAndy Adamson 555c6b0a9f8SNeilBrown pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. 556c6b0a9f8SNeilBrown * We assume one is at most one page 557c6b0a9f8SNeilBrown */ 5581da177e4SLinus Torvalds arghi = 0; 559b25cd058SWeston Andros Adamson WARN_ON_ONCE(pages > RPCSVC_MAXPAGES); 560b25cd058SWeston Andros Adamson if (pages > RPCSVC_MAXPAGES) 561b25cd058SWeston Andros Adamson pages = RPCSVC_MAXPAGES; 5621da177e4SLinus Torvalds while (pages) { 56311fd165cSEric Dumazet struct page *p = alloc_pages_node(node, GFP_KERNEL, 0); 5641da177e4SLinus Torvalds if (!p) 5651da177e4SLinus Torvalds break; 56644524359SNeilBrown rqstp->rq_pages[arghi++] = p; 5671da177e4SLinus Torvalds pages--; 5681da177e4SLinus Torvalds } 5690dc220f0SChuck Lever return pages == 0; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds /* 5731da177e4SLinus Torvalds * Release an RPC server buffer 5741da177e4SLinus Torvalds */ 5751da177e4SLinus Torvalds static void 5761da177e4SLinus Torvalds svc_release_buffer(struct svc_rqst *rqstp) 5771da177e4SLinus Torvalds { 57850c8bb13SChuck Lever unsigned int i; 57950c8bb13SChuck Lever 58044524359SNeilBrown for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) 58144524359SNeilBrown if (rqstp->rq_pages[i]) 58244524359SNeilBrown put_page(rqstp->rq_pages[i]); 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds 5850113ab34SJeff Layton struct svc_rqst * 5861b6dc1dfSJeff Layton svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) 5870113ab34SJeff Layton { 5880113ab34SJeff Layton struct svc_rqst *rqstp; 5890113ab34SJeff Layton 59011fd165cSEric Dumazet rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node); 5910113ab34SJeff Layton if (!rqstp) 5921b6dc1dfSJeff Layton return rqstp; 5930113ab34SJeff Layton 594b1691bc0SJeff Layton __set_bit(RQ_BUSY, &rqstp->rq_flags); 595b1691bc0SJeff Layton spin_lock_init(&rqstp->rq_lock); 596b1691bc0SJeff Layton rqstp->rq_server = serv; 597b1691bc0SJeff Layton rqstp->rq_pool = pool; 5981b6dc1dfSJeff Layton 5991b6dc1dfSJeff Layton rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6001b6dc1dfSJeff Layton if (!rqstp->rq_argp) 6011b6dc1dfSJeff Layton goto out_enomem; 6021b6dc1dfSJeff Layton 6031b6dc1dfSJeff Layton rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 6041b6dc1dfSJeff Layton if (!rqstp->rq_resp) 6051b6dc1dfSJeff Layton goto out_enomem; 6061b6dc1dfSJeff Layton 6071b6dc1dfSJeff Layton if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node)) 6081b6dc1dfSJeff Layton goto out_enomem; 6091b6dc1dfSJeff Layton 6101b6dc1dfSJeff Layton return rqstp; 6111b6dc1dfSJeff Layton out_enomem: 6121b6dc1dfSJeff Layton svc_rqst_free(rqstp); 6131b6dc1dfSJeff Layton return NULL; 6141b6dc1dfSJeff Layton } 6151b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_alloc); 6161b6dc1dfSJeff Layton 6171b6dc1dfSJeff Layton struct svc_rqst * 6181b6dc1dfSJeff Layton svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) 6191b6dc1dfSJeff Layton { 6201b6dc1dfSJeff Layton struct svc_rqst *rqstp; 6211b6dc1dfSJeff Layton 6221b6dc1dfSJeff Layton rqstp = svc_rqst_alloc(serv, pool, node); 6231b6dc1dfSJeff Layton if (!rqstp) 6241b6dc1dfSJeff Layton return ERR_PTR(-ENOMEM); 6251b6dc1dfSJeff Layton 6261b6dc1dfSJeff Layton serv->sv_nrthreads++; 6270113ab34SJeff Layton spin_lock_bh(&pool->sp_lock); 6280113ab34SJeff Layton pool->sp_nrthreads++; 62981244386SJeff Layton list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); 6300113ab34SJeff Layton spin_unlock_bh(&pool->sp_lock); 6310113ab34SJeff Layton return rqstp; 6320113ab34SJeff Layton } 63324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_prepare_thread); 6340113ab34SJeff Layton 6351da177e4SLinus Torvalds /* 636a7455442SGreg Banks * Choose a pool in which to create a new thread, for svc_set_num_threads 637a7455442SGreg Banks */ 638a7455442SGreg Banks static inline struct svc_pool * 639a7455442SGreg Banks choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 640a7455442SGreg Banks { 641a7455442SGreg Banks if (pool != NULL) 642a7455442SGreg Banks return pool; 643a7455442SGreg Banks 644a7455442SGreg Banks return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; 645a7455442SGreg Banks } 646a7455442SGreg Banks 647a7455442SGreg Banks /* 648a7455442SGreg Banks * Choose a thread to kill, for svc_set_num_threads 649a7455442SGreg Banks */ 650a7455442SGreg Banks static inline struct task_struct * 651a7455442SGreg Banks choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 652a7455442SGreg Banks { 653a7455442SGreg Banks unsigned int i; 654a7455442SGreg Banks struct task_struct *task = NULL; 655a7455442SGreg Banks 656a7455442SGreg Banks if (pool != NULL) { 657a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 658a7455442SGreg Banks } else { 659a7455442SGreg Banks /* choose a pool in round-robin fashion */ 660a7455442SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 661a7455442SGreg Banks pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; 662a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 663a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) 664a7455442SGreg Banks goto found_pool; 665a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 666a7455442SGreg Banks } 667a7455442SGreg Banks return NULL; 668a7455442SGreg Banks } 669a7455442SGreg Banks 670a7455442SGreg Banks found_pool: 671a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) { 672a7455442SGreg Banks struct svc_rqst *rqstp; 673a7455442SGreg Banks 674a7455442SGreg Banks /* 675a7455442SGreg Banks * Remove from the pool->sp_all_threads list 676a7455442SGreg Banks * so we don't try to kill it again. 677a7455442SGreg Banks */ 678a7455442SGreg Banks rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); 67981244386SJeff Layton set_bit(RQ_VICTIM, &rqstp->rq_flags); 68081244386SJeff Layton list_del_rcu(&rqstp->rq_all); 681a7455442SGreg Banks task = rqstp->rq_task; 682a7455442SGreg Banks } 683a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 684a7455442SGreg Banks 685a7455442SGreg Banks return task; 686a7455442SGreg Banks } 687a7455442SGreg Banks 688a7455442SGreg Banks /* 689a7455442SGreg Banks * Create or destroy enough new threads to make the number 690a7455442SGreg Banks * of threads the given number. If `pool' is non-NULL, applies 691a7455442SGreg Banks * only to threads in that pool, otherwise round-robins between 69294cf3179SJ. Bruce Fields * all pools. Caller must ensure that mutual exclusion between this and 69394cf3179SJ. Bruce Fields * server startup or shutdown. 694a7455442SGreg Banks * 695a7455442SGreg Banks * Destroying threads relies on the service threads filling in 696a7455442SGreg Banks * rqstp->rq_task, which only the nfs ones do. Assumes the serv 697a7455442SGreg Banks * has been created using svc_create_pooled(). 698a7455442SGreg Banks * 699a7455442SGreg Banks * Based on code that used to be in nfsd_svc() but tweaked 700a7455442SGreg Banks * to be pool-aware. 701a7455442SGreg Banks */ 702a7455442SGreg Banks int 703a7455442SGreg Banks svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 704a7455442SGreg Banks { 7059867d76cSJeff Layton struct svc_rqst *rqstp; 7069867d76cSJeff Layton struct task_struct *task; 7079867d76cSJeff Layton struct svc_pool *chosen_pool; 708a7455442SGreg Banks int error = 0; 709a7455442SGreg Banks unsigned int state = serv->sv_nrthreads-1; 71011fd165cSEric Dumazet int node; 711a7455442SGreg Banks 712a7455442SGreg Banks if (pool == NULL) { 713a7455442SGreg Banks /* The -1 assumes caller has done a svc_get() */ 714a7455442SGreg Banks nrservs -= (serv->sv_nrthreads-1); 715a7455442SGreg Banks } else { 716a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 717a7455442SGreg Banks nrservs -= pool->sp_nrthreads; 718a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 719a7455442SGreg Banks } 720a7455442SGreg Banks 721a7455442SGreg Banks /* create new threads */ 722a7455442SGreg Banks while (nrservs > 0) { 723a7455442SGreg Banks nrservs--; 7249867d76cSJeff Layton chosen_pool = choose_pool(serv, pool, &state); 7259867d76cSJeff Layton 72611fd165cSEric Dumazet node = svc_pool_map_get_node(chosen_pool->sp_id); 72711fd165cSEric Dumazet rqstp = svc_prepare_thread(serv, chosen_pool, node); 7289867d76cSJeff Layton if (IS_ERR(rqstp)) { 7299867d76cSJeff Layton error = PTR_ERR(rqstp); 730a7455442SGreg Banks break; 731a7455442SGreg Banks } 7329867d76cSJeff Layton 733758f62ffSJeff Layton __module_get(serv->sv_ops->svo_module); 734c369014fSJeff Layton task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp, 735f170168bSKees Cook node, "%s", serv->sv_name); 7369867d76cSJeff Layton if (IS_ERR(task)) { 7379867d76cSJeff Layton error = PTR_ERR(task); 738758f62ffSJeff Layton module_put(serv->sv_ops->svo_module); 7399867d76cSJeff Layton svc_exit_thread(rqstp); 7409867d76cSJeff Layton break; 7419867d76cSJeff Layton } 7429867d76cSJeff Layton 7439867d76cSJeff Layton rqstp->rq_task = task; 7449867d76cSJeff Layton if (serv->sv_nrpools > 1) 7459867d76cSJeff Layton svc_pool_map_set_cpumask(task, chosen_pool->sp_id); 7469867d76cSJeff Layton 7479867d76cSJeff Layton svc_sock_update_bufs(serv); 7489867d76cSJeff Layton wake_up_process(task); 749a7455442SGreg Banks } 750a7455442SGreg Banks /* destroy old threads */ 751a7455442SGreg Banks while (nrservs < 0 && 7529867d76cSJeff Layton (task = choose_victim(serv, pool, &state)) != NULL) { 753a75c5d01SJeff Layton send_sig(SIGINT, task, 1); 754a7455442SGreg Banks nrservs++; 755a7455442SGreg Banks } 756a7455442SGreg Banks 757a7455442SGreg Banks return error; 758a7455442SGreg Banks } 75924c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_set_num_threads); 760a7455442SGreg Banks 761a7455442SGreg Banks /* 7623c519914SJeff Layton * Called from a server thread as it's exiting. Caller must hold the "service 7633c519914SJeff Layton * mutex" for the service. 7641da177e4SLinus Torvalds */ 7651da177e4SLinus Torvalds void 7661b6dc1dfSJeff Layton svc_rqst_free(struct svc_rqst *rqstp) 7671da177e4SLinus Torvalds { 7681da177e4SLinus Torvalds svc_release_buffer(rqstp); 7691da177e4SLinus Torvalds kfree(rqstp->rq_resp); 7701da177e4SLinus Torvalds kfree(rqstp->rq_argp); 7711da177e4SLinus Torvalds kfree(rqstp->rq_auth_data); 7721b6dc1dfSJeff Layton kfree_rcu(rqstp, rq_rcu_head); 7731b6dc1dfSJeff Layton } 7741b6dc1dfSJeff Layton EXPORT_SYMBOL_GPL(svc_rqst_free); 7751b6dc1dfSJeff Layton 7761b6dc1dfSJeff Layton void 7771b6dc1dfSJeff Layton svc_exit_thread(struct svc_rqst *rqstp) 7781b6dc1dfSJeff Layton { 7791b6dc1dfSJeff Layton struct svc_serv *serv = rqstp->rq_server; 7801b6dc1dfSJeff Layton struct svc_pool *pool = rqstp->rq_pool; 7813262c816SGreg Banks 7823262c816SGreg Banks spin_lock_bh(&pool->sp_lock); 7833262c816SGreg Banks pool->sp_nrthreads--; 78481244386SJeff Layton if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags)) 78581244386SJeff Layton list_del_rcu(&rqstp->rq_all); 7863262c816SGreg Banks spin_unlock_bh(&pool->sp_lock); 7873262c816SGreg Banks 7881b6dc1dfSJeff Layton svc_rqst_free(rqstp); 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* Release the server */ 7911da177e4SLinus Torvalds if (serv) 7921da177e4SLinus Torvalds svc_destroy(serv); 7931da177e4SLinus Torvalds } 79424c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_exit_thread); 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds /* 7972c7eb0b2SChuck Lever * Register an "inet" protocol family netid with the local 7982c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 799a26cfad6SChuck Lever * 8002c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8012c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 802a26cfad6SChuck Lever * 8032c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8042c7eb0b2SChuck Lever * if any error occurs. 8051da177e4SLinus Torvalds */ 8065247fab5SStanislav Kinsbursky static int __svc_rpcb_register4(struct net *net, const u32 program, 8075247fab5SStanislav Kinsbursky const u32 version, 808a26cfad6SChuck Lever const unsigned short protocol, 809a26cfad6SChuck Lever const unsigned short port) 810a26cfad6SChuck Lever { 811cadc0fa5SChuck Lever const struct sockaddr_in sin = { 812a26cfad6SChuck Lever .sin_family = AF_INET, 813a26cfad6SChuck Lever .sin_addr.s_addr = htonl(INADDR_ANY), 814a26cfad6SChuck Lever .sin_port = htons(port), 815a26cfad6SChuck Lever }; 816cadc0fa5SChuck Lever const char *netid; 817cadc0fa5SChuck Lever int error; 8182c7eb0b2SChuck Lever 8192c7eb0b2SChuck Lever switch (protocol) { 8202c7eb0b2SChuck Lever case IPPROTO_UDP: 8212c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP; 8222c7eb0b2SChuck Lever break; 8232c7eb0b2SChuck Lever case IPPROTO_TCP: 8242c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP; 8252c7eb0b2SChuck Lever break; 8262c7eb0b2SChuck Lever default: 827ba5c35e0SChuck Lever return -ENOPROTOOPT; 8282c7eb0b2SChuck Lever } 8292c7eb0b2SChuck Lever 8305247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 831cadc0fa5SChuck Lever (const struct sockaddr *)&sin, netid); 832cadc0fa5SChuck Lever 833cadc0fa5SChuck Lever /* 834cadc0fa5SChuck Lever * User space didn't support rpcbind v4, so retry this 835cadc0fa5SChuck Lever * registration request with the legacy rpcbind v2 protocol. 836cadc0fa5SChuck Lever */ 837cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 8385247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, protocol, port); 839cadc0fa5SChuck Lever 840cadc0fa5SChuck Lever return error; 8412c7eb0b2SChuck Lever } 8422c7eb0b2SChuck Lever 843dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 8442c7eb0b2SChuck Lever /* 8452c7eb0b2SChuck Lever * Register an "inet6" protocol family netid with the local 8462c7eb0b2SChuck Lever * rpcbind daemon via an rpcbind v4 SET request. 8472c7eb0b2SChuck Lever * 8482c7eb0b2SChuck Lever * No netconfig infrastructure is available in the kernel, so 8492c7eb0b2SChuck Lever * we map IP_ protocol numbers to netids by hand. 8502c7eb0b2SChuck Lever * 8512c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8522c7eb0b2SChuck Lever * if any error occurs. 8532c7eb0b2SChuck Lever */ 8545247fab5SStanislav Kinsbursky static int __svc_rpcb_register6(struct net *net, const u32 program, 8555247fab5SStanislav Kinsbursky const u32 version, 8562c7eb0b2SChuck Lever const unsigned short protocol, 8572c7eb0b2SChuck Lever const unsigned short port) 8582c7eb0b2SChuck Lever { 859cadc0fa5SChuck Lever const struct sockaddr_in6 sin6 = { 860a26cfad6SChuck Lever .sin6_family = AF_INET6, 861a26cfad6SChuck Lever .sin6_addr = IN6ADDR_ANY_INIT, 862a26cfad6SChuck Lever .sin6_port = htons(port), 863a26cfad6SChuck Lever }; 864cadc0fa5SChuck Lever const char *netid; 865cadc0fa5SChuck Lever int error; 866a26cfad6SChuck Lever 8672c7eb0b2SChuck Lever switch (protocol) { 8682c7eb0b2SChuck Lever case IPPROTO_UDP: 8692c7eb0b2SChuck Lever netid = RPCBIND_NETID_UDP6; 8702c7eb0b2SChuck Lever break; 8712c7eb0b2SChuck Lever case IPPROTO_TCP: 8722c7eb0b2SChuck Lever netid = RPCBIND_NETID_TCP6; 8732c7eb0b2SChuck Lever break; 8742c7eb0b2SChuck Lever default: 875ba5c35e0SChuck Lever return -ENOPROTOOPT; 8762c7eb0b2SChuck Lever } 8772c7eb0b2SChuck Lever 8785247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, 879cadc0fa5SChuck Lever (const struct sockaddr *)&sin6, netid); 880cadc0fa5SChuck Lever 881cadc0fa5SChuck Lever /* 882cadc0fa5SChuck Lever * User space didn't support rpcbind version 4, so we won't 883cadc0fa5SChuck Lever * use a PF_INET6 listener. 884cadc0fa5SChuck Lever */ 885cadc0fa5SChuck Lever if (error == -EPROTONOSUPPORT) 886cadc0fa5SChuck Lever error = -EAFNOSUPPORT; 887cadc0fa5SChuck Lever 888cadc0fa5SChuck Lever return error; 8892c7eb0b2SChuck Lever } 890dfd56b8bSEric Dumazet #endif /* IS_ENABLED(CONFIG_IPV6) */ 8912c7eb0b2SChuck Lever 8922c7eb0b2SChuck Lever /* 8932c7eb0b2SChuck Lever * Register a kernel RPC service via rpcbind version 4. 8942c7eb0b2SChuck Lever * 8952c7eb0b2SChuck Lever * Returns zero on success; a negative errno value is returned 8962c7eb0b2SChuck Lever * if any error occurs. 8972c7eb0b2SChuck Lever */ 8985247fab5SStanislav Kinsbursky static int __svc_register(struct net *net, const char *progname, 899363f724cSChuck Lever const u32 program, const u32 version, 9004b62e58cSChuck Lever const int family, 9012c7eb0b2SChuck Lever const unsigned short protocol, 9022c7eb0b2SChuck Lever const unsigned short port) 9032c7eb0b2SChuck Lever { 904363f724cSChuck Lever int error = -EAFNOSUPPORT; 9052c7eb0b2SChuck Lever 906a26cfad6SChuck Lever switch (family) { 9074b62e58cSChuck Lever case PF_INET: 9085247fab5SStanislav Kinsbursky error = __svc_rpcb_register4(net, program, version, 9092c7eb0b2SChuck Lever protocol, port); 910cadc0fa5SChuck Lever break; 911dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 9124b62e58cSChuck Lever case PF_INET6: 9135247fab5SStanislav Kinsbursky error = __svc_rpcb_register6(net, program, version, 9142c7eb0b2SChuck Lever protocol, port); 915dfd56b8bSEric Dumazet #endif 9162c7eb0b2SChuck Lever } 9172c7eb0b2SChuck Lever 918a26cfad6SChuck Lever return error; 919a26cfad6SChuck Lever } 920a26cfad6SChuck Lever 921a26cfad6SChuck Lever /** 922a26cfad6SChuck Lever * svc_register - register an RPC service with the local portmapper 923a26cfad6SChuck Lever * @serv: svc_serv struct for the service to register 9245247fab5SStanislav Kinsbursky * @net: net namespace for the service to register 9254b62e58cSChuck Lever * @family: protocol family of service's listener socket 926a26cfad6SChuck Lever * @proto: transport protocol number to advertise 927a26cfad6SChuck Lever * @port: port to advertise 928a26cfad6SChuck Lever * 9294b62e58cSChuck Lever * Service is registered for any address in the passed-in protocol family 930a26cfad6SChuck Lever */ 9315247fab5SStanislav Kinsbursky int svc_register(const struct svc_serv *serv, struct net *net, 9325247fab5SStanislav Kinsbursky const int family, const unsigned short proto, 9335247fab5SStanislav Kinsbursky const unsigned short port) 9341da177e4SLinus Torvalds { 9351da177e4SLinus Torvalds struct svc_program *progp; 9367e55b59bSKinglong Mee struct svc_version *vers; 937ea339d46SChuck Lever unsigned int i; 93814aeb211SChuck Lever int error = 0; 9391da177e4SLinus Torvalds 9400af39507SWeston Andros Adamson WARN_ON_ONCE(proto == 0 && port == 0); 9410af39507SWeston Andros Adamson if (proto == 0 && port == 0) 9420af39507SWeston Andros Adamson return -EINVAL; 9431da177e4SLinus Torvalds 944bc5fea42SOlaf Kirch for (progp = serv->sv_program; progp; progp = progp->pg_next) { 9451da177e4SLinus Torvalds for (i = 0; i < progp->pg_nvers; i++) { 9467e55b59bSKinglong Mee vers = progp->pg_vers[i]; 9477e55b59bSKinglong Mee if (vers == NULL) 9481da177e4SLinus Torvalds continue; 949bc5fea42SOlaf Kirch 9502c7eb0b2SChuck Lever dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", 951bc5fea42SOlaf Kirch progp->pg_name, 9522c7eb0b2SChuck Lever i, 953bc5fea42SOlaf Kirch proto == IPPROTO_UDP? "udp" : "tcp", 954bc5fea42SOlaf Kirch port, 9554b62e58cSChuck Lever family, 9567e55b59bSKinglong Mee vers->vs_hidden ? 957bc5fea42SOlaf Kirch " (but not telling portmap)" : ""); 958bc5fea42SOlaf Kirch 9597e55b59bSKinglong Mee if (vers->vs_hidden) 960bc5fea42SOlaf Kirch continue; 961bc5fea42SOlaf Kirch 9625247fab5SStanislav Kinsbursky error = __svc_register(net, progp->pg_name, progp->pg_prog, 963363f724cSChuck Lever i, family, proto, port); 9647e55b59bSKinglong Mee 9657e55b59bSKinglong Mee if (vers->vs_rpcb_optnl) { 9667e55b59bSKinglong Mee error = 0; 9677e55b59bSKinglong Mee continue; 9687e55b59bSKinglong Mee } 9697e55b59bSKinglong Mee 9707e55b59bSKinglong Mee if (error < 0) { 9717e55b59bSKinglong Mee printk(KERN_WARNING "svc: failed to register " 9727e55b59bSKinglong Mee "%sv%u RPC service (errno %d).\n", 9737e55b59bSKinglong Mee progp->pg_name, i, -error); 9741da177e4SLinus Torvalds break; 9751da177e4SLinus Torvalds } 976bc5fea42SOlaf Kirch } 9777e55b59bSKinglong Mee } 9781da177e4SLinus Torvalds 9797252d575SChuck Lever return error; 9807252d575SChuck Lever } 9817252d575SChuck Lever 982d5a8620fSChuck Lever /* 983d5a8620fSChuck Lever * If user space is running rpcbind, it should take the v4 UNSET 984d5a8620fSChuck Lever * and clear everything for this [program, version]. If user space 985d5a8620fSChuck Lever * is running portmap, it will reject the v4 UNSET, but won't have 986d5a8620fSChuck Lever * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient 987d5a8620fSChuck Lever * in this case to clear all existing entries for [program, version]. 988d5a8620fSChuck Lever */ 9895247fab5SStanislav Kinsbursky static void __svc_unregister(struct net *net, const u32 program, const u32 version, 990f6fb3f6fSChuck Lever const char *progname) 991f6fb3f6fSChuck Lever { 992f6fb3f6fSChuck Lever int error; 993f6fb3f6fSChuck Lever 9945247fab5SStanislav Kinsbursky error = rpcb_v4_register(net, program, version, NULL, ""); 995d5a8620fSChuck Lever 996d5a8620fSChuck Lever /* 997d5a8620fSChuck Lever * User space didn't support rpcbind v4, so retry this 998d5a8620fSChuck Lever * request with the legacy rpcbind v2 protocol. 999d5a8620fSChuck Lever */ 1000d5a8620fSChuck Lever if (error == -EPROTONOSUPPORT) 10015247fab5SStanislav Kinsbursky error = rpcb_register(net, program, version, 0, 0); 1002d5a8620fSChuck Lever 1003f6fb3f6fSChuck Lever dprintk("svc: %s(%sv%u), error %d\n", 1004f6fb3f6fSChuck Lever __func__, progname, version, error); 1005f6fb3f6fSChuck Lever } 1006f6fb3f6fSChuck Lever 10077252d575SChuck Lever /* 1008f6fb3f6fSChuck Lever * All netids, bind addresses and ports registered for [program, version] 1009f6fb3f6fSChuck Lever * are removed from the local rpcbind database (if the service is not 1010f6fb3f6fSChuck Lever * hidden) to make way for a new instance of the service. 10117252d575SChuck Lever * 1012f6fb3f6fSChuck Lever * The result of unregistration is reported via dprintk for those who want 1013f6fb3f6fSChuck Lever * verification of the result, but is otherwise not important. 10147252d575SChuck Lever */ 10155247fab5SStanislav Kinsbursky static void svc_unregister(const struct svc_serv *serv, struct net *net) 10167252d575SChuck Lever { 10177252d575SChuck Lever struct svc_program *progp; 10187252d575SChuck Lever unsigned long flags; 10197252d575SChuck Lever unsigned int i; 10207252d575SChuck Lever 10217252d575SChuck Lever clear_thread_flag(TIF_SIGPENDING); 10227252d575SChuck Lever 10237252d575SChuck Lever for (progp = serv->sv_program; progp; progp = progp->pg_next) { 10247252d575SChuck Lever for (i = 0; i < progp->pg_nvers; i++) { 10257252d575SChuck Lever if (progp->pg_vers[i] == NULL) 10267252d575SChuck Lever continue; 10277252d575SChuck Lever if (progp->pg_vers[i]->vs_hidden) 10287252d575SChuck Lever continue; 10297252d575SChuck Lever 10307402ab19SChuck Lever dprintk("svc: attempting to unregister %sv%u\n", 10317402ab19SChuck Lever progp->pg_name, i); 10325247fab5SStanislav Kinsbursky __svc_unregister(net, progp->pg_prog, i, progp->pg_name); 10337252d575SChuck Lever } 10347252d575SChuck Lever } 10357252d575SChuck Lever 10361da177e4SLinus Torvalds spin_lock_irqsave(¤t->sighand->siglock, flags); 10371da177e4SLinus Torvalds recalc_sigpending(); 10381da177e4SLinus Torvalds spin_unlock_irqrestore(¤t->sighand->siglock, flags); 10391da177e4SLinus Torvalds } 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds /* 10427032a3ddSJ. Bruce Fields * dprintk the given error with the address of the client that caused it. 1043354ecbb9SDr. David Alan Gilbert */ 1044f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 1045b9075fa9SJoe Perches static __printf(2, 3) 1046e87cc472SJoe Perches void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) 1047354ecbb9SDr. David Alan Gilbert { 1048e87cc472SJoe Perches struct va_format vaf; 1049354ecbb9SDr. David Alan Gilbert va_list args; 1050354ecbb9SDr. David Alan Gilbert char buf[RPC_MAX_ADDRBUFLEN]; 1051354ecbb9SDr. David Alan Gilbert 1052354ecbb9SDr. David Alan Gilbert va_start(args, fmt); 1053354ecbb9SDr. David Alan Gilbert 1054e87cc472SJoe Perches vaf.fmt = fmt; 1055e87cc472SJoe Perches vaf.va = &args; 1056e87cc472SJoe Perches 10577032a3ddSJ. Bruce Fields dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); 1058e87cc472SJoe Perches 1059e87cc472SJoe Perches va_end(args); 1060354ecbb9SDr. David Alan Gilbert } 1061624ab464SJ. Bruce Fields #else 1062624ab464SJ. Bruce Fields static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} 1063624ab464SJ. Bruce Fields #endif 1064354ecbb9SDr. David Alan Gilbert 1065354ecbb9SDr. David Alan Gilbert /* 10661cad7ea6SRicardo Labiaga * Common routine for processing the RPC request. 10671da177e4SLinus Torvalds */ 10681cad7ea6SRicardo Labiaga static int 10691cad7ea6SRicardo Labiaga svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) 10701da177e4SLinus Torvalds { 10711da177e4SLinus Torvalds struct svc_program *progp; 10721da177e4SLinus Torvalds struct svc_version *versp = NULL; /* compiler food */ 10731da177e4SLinus Torvalds struct svc_procedure *procp = NULL; 10746fb2b47fSNeilBrown struct svc_serv *serv = rqstp->rq_server; 10751da177e4SLinus Torvalds kxdrproc_t xdr; 1076d8ed029dSAlexey Dobriyan __be32 *statp; 10771cad7ea6SRicardo Labiaga u32 prog, vers, proc; 1078d8ed029dSAlexey Dobriyan __be32 auth_stat, rpc_stat; 10791da177e4SLinus Torvalds int auth_res; 10808f8e05c5SJ.Bruce Fields __be32 *reply_statp; 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds rpc_stat = rpc_success; 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds if (argv->iov_len < 6*4) 10851da177e4SLinus Torvalds goto err_short_len; 10861da177e4SLinus Torvalds 10875c04c46aSJ. Bruce Fields /* Will be turned off only in gss privacy case: */ 1088779fb0f3SJeff Layton set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); 10892f425878SAndy Adamson /* Will be turned off only when NFSv4 Sessions are used */ 109030660e04SJeff Layton set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); 109178b65eb3SJeff Layton clear_bit(RQ_DROPME, &rqstp->rq_flags); 1092e831fe65STom Tucker 1093e831fe65STom Tucker /* Setup reply header */ 1094e831fe65STom Tucker rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds svc_putu32(resv, rqstp->rq_xid); 10971da177e4SLinus Torvalds 109876994313SAlexey Dobriyan vers = svc_getnl(argv); 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds /* First words of reply: */ 110176994313SAlexey Dobriyan svc_putnl(resv, 1); /* REPLY */ 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds if (vers != 2) /* RPC version number */ 11041da177e4SLinus Torvalds goto err_bad_rpc; 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds /* Save position in case we later decide to reject: */ 11078f8e05c5SJ.Bruce Fields reply_statp = resv->iov_base + resv->iov_len; 11081da177e4SLinus Torvalds 110976994313SAlexey Dobriyan svc_putnl(resv, 0); /* ACCEPT */ 11101da177e4SLinus Torvalds 111176994313SAlexey Dobriyan rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ 111276994313SAlexey Dobriyan rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ 111376994313SAlexey Dobriyan rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ 11141da177e4SLinus Torvalds 111580d188a6SNeilBrown for (progp = serv->sv_program; progp; progp = progp->pg_next) 111680d188a6SNeilBrown if (prog == progp->pg_prog) 111780d188a6SNeilBrown break; 111880d188a6SNeilBrown 11191da177e4SLinus Torvalds /* 11201da177e4SLinus Torvalds * Decode auth data, and add verifier to reply buffer. 11211da177e4SLinus Torvalds * We do this before anything else in order to get a decent 11221da177e4SLinus Torvalds * auth verifier. 11231da177e4SLinus Torvalds */ 11241da177e4SLinus Torvalds auth_res = svc_authenticate(rqstp, &auth_stat); 11251da177e4SLinus Torvalds /* Also give the program a chance to reject this call: */ 112680d188a6SNeilBrown if (auth_res == SVC_OK && progp) { 11271da177e4SLinus Torvalds auth_stat = rpc_autherr_badcred; 11281da177e4SLinus Torvalds auth_res = progp->pg_authenticate(rqstp); 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds switch (auth_res) { 11311da177e4SLinus Torvalds case SVC_OK: 11321da177e4SLinus Torvalds break; 11331da177e4SLinus Torvalds case SVC_GARBAGE: 1134dd35210eSHarshula Jayasuriya goto err_garbage; 11351da177e4SLinus Torvalds case SVC_SYSERR: 11361da177e4SLinus Torvalds rpc_stat = rpc_system_err; 11371da177e4SLinus Torvalds goto err_bad; 11381da177e4SLinus Torvalds case SVC_DENIED: 11391da177e4SLinus Torvalds goto err_bad_auth; 11401ebede86SNeilBrown case SVC_CLOSE: 11411ebede86SNeilBrown if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) 11421ebede86SNeilBrown svc_close_xprt(rqstp->rq_xprt); 11431da177e4SLinus Torvalds case SVC_DROP: 11441da177e4SLinus Torvalds goto dropit; 11451da177e4SLinus Torvalds case SVC_COMPLETE: 11461da177e4SLinus Torvalds goto sendit; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds 11499ba02638SAndreas Gruenbacher if (progp == NULL) 11501da177e4SLinus Torvalds goto err_bad_prog; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds if (vers >= progp->pg_nvers || 11531da177e4SLinus Torvalds !(versp = progp->pg_vers[vers])) 11541da177e4SLinus Torvalds goto err_bad_vers; 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds procp = versp->vs_proc + proc; 11571da177e4SLinus Torvalds if (proc >= versp->vs_nproc || !procp->pc_func) 11581da177e4SLinus Torvalds goto err_bad_proc; 11591da177e4SLinus Torvalds rqstp->rq_procinfo = procp; 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds /* Syntactic check complete */ 11621da177e4SLinus Torvalds serv->sv_stats->rpccnt++; 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds /* Build the reply header. */ 11651da177e4SLinus Torvalds statp = resv->iov_base +resv->iov_len; 116676994313SAlexey Dobriyan svc_putnl(resv, RPC_SUCCESS); 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds /* Bump per-procedure stats counter */ 11691da177e4SLinus Torvalds procp->pc_count++; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds /* Initialize storage for argp and resp */ 11721da177e4SLinus Torvalds memset(rqstp->rq_argp, 0, procp->pc_argsize); 11731da177e4SLinus Torvalds memset(rqstp->rq_resp, 0, procp->pc_ressize); 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds /* un-reserve some of the out-queue now that we have a 11761da177e4SLinus Torvalds * better idea of reply size 11771da177e4SLinus Torvalds */ 11781da177e4SLinus Torvalds if (procp->pc_xdrressize) 1179cd123012SJeff Layton svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* Call the function that processes the request. */ 11821da177e4SLinus Torvalds if (!versp->vs_dispatch) { 11831da177e4SLinus Torvalds /* Decode arguments */ 11841da177e4SLinus Torvalds xdr = procp->pc_decode; 11851da177e4SLinus Torvalds if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) 11861da177e4SLinus Torvalds goto err_garbage; 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds /* Encode reply */ 119178b65eb3SJeff Layton if (test_bit(RQ_DROPME, &rqstp->rq_flags)) { 1192d343fce1SNeilBrown if (procp->pc_release) 1193d343fce1SNeilBrown procp->pc_release(rqstp, NULL, rqstp->rq_resp); 1194d343fce1SNeilBrown goto dropit; 1195d343fce1SNeilBrown } 1196f64f9e71SJoe Perches if (*statp == rpc_success && 1197f64f9e71SJoe Perches (xdr = procp->pc_encode) && 1198f64f9e71SJoe Perches !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { 11991da177e4SLinus Torvalds dprintk("svc: failed to encode reply\n"); 12001da177e4SLinus Torvalds /* serv->sv_stats->rpcsystemerr++; */ 12011da177e4SLinus Torvalds *statp = rpc_system_err; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds } else { 12041da177e4SLinus Torvalds dprintk("svc: calling dispatcher\n"); 12051da177e4SLinus Torvalds if (!versp->vs_dispatch(rqstp, statp)) { 12061da177e4SLinus Torvalds /* Release reply info */ 12071da177e4SLinus Torvalds if (procp->pc_release) 12081da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12091da177e4SLinus Torvalds goto dropit; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds /* Check RPC status result */ 12141da177e4SLinus Torvalds if (*statp != rpc_success) 12151da177e4SLinus Torvalds resv->iov_len = ((void*)statp) - resv->iov_base + 4; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds /* Release reply info */ 12181da177e4SLinus Torvalds if (procp->pc_release) 12191da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds if (procp->pc_encode == NULL) 12221da177e4SLinus Torvalds goto dropit; 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds sendit: 12251da177e4SLinus Torvalds if (svc_authorise(rqstp)) 12261da177e4SLinus Torvalds goto dropit; 12271cad7ea6SRicardo Labiaga return 1; /* Caller can now send it */ 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds dropit: 12301da177e4SLinus Torvalds svc_authorise(rqstp); /* doesn't hurt to call this twice */ 12311da177e4SLinus Torvalds dprintk("svc: svc_process dropit\n"); 12321da177e4SLinus Torvalds return 0; 12331da177e4SLinus Torvalds 12341da177e4SLinus Torvalds err_short_len: 1235354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "short len %Zd, dropping request\n", 1236354ecbb9SDr. David Alan Gilbert argv->iov_len); 123734e9a63bSNeilBrown 12381da177e4SLinus Torvalds goto dropit; /* drop request */ 12391da177e4SLinus Torvalds 12401da177e4SLinus Torvalds err_bad_rpc: 12411da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 124276994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 124376994313SAlexey Dobriyan svc_putnl(resv, 0); /* RPC_MISMATCH */ 124476994313SAlexey Dobriyan svc_putnl(resv, 2); /* Only RPCv2 supported */ 124576994313SAlexey Dobriyan svc_putnl(resv, 2); 12461da177e4SLinus Torvalds goto sendit; 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds err_bad_auth: 12491da177e4SLinus Torvalds dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); 12501da177e4SLinus Torvalds serv->sv_stats->rpcbadauth++; 12511da177e4SLinus Torvalds /* Restore write pointer to location of accept status: */ 12528f8e05c5SJ.Bruce Fields xdr_ressize_check(rqstp, reply_statp); 125376994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 125476994313SAlexey Dobriyan svc_putnl(resv, 1); /* AUTH_ERROR */ 125576994313SAlexey Dobriyan svc_putnl(resv, ntohl(auth_stat)); /* status */ 12561da177e4SLinus Torvalds goto sendit; 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds err_bad_prog: 12599ba02638SAndreas Gruenbacher dprintk("svc: unknown program %d\n", prog); 12601da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 126176994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_UNAVAIL); 12621da177e4SLinus Torvalds goto sendit; 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds err_bad_vers: 1265354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", 12661a8eff6dSNeilBrown vers, prog, progp->pg_name); 126734e9a63bSNeilBrown 12681da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 126976994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_MISMATCH); 127076994313SAlexey Dobriyan svc_putnl(resv, progp->pg_lovers); 127176994313SAlexey Dobriyan svc_putnl(resv, progp->pg_hivers); 12721da177e4SLinus Torvalds goto sendit; 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds err_bad_proc: 1275354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown procedure (%d)\n", proc); 127634e9a63bSNeilBrown 12771da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 127876994313SAlexey Dobriyan svc_putnl(resv, RPC_PROC_UNAVAIL); 12791da177e4SLinus Torvalds goto sendit; 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds err_garbage: 1282354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "failed to decode args\n"); 128334e9a63bSNeilBrown 12841da177e4SLinus Torvalds rpc_stat = rpc_garbage_args; 12851da177e4SLinus Torvalds err_bad: 12861da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 128776994313SAlexey Dobriyan svc_putnl(resv, ntohl(rpc_stat)); 12881da177e4SLinus Torvalds goto sendit; 12891da177e4SLinus Torvalds } 12907adae489SGreg Banks 12917adae489SGreg Banks /* 12921cad7ea6SRicardo Labiaga * Process the RPC request. 12931cad7ea6SRicardo Labiaga */ 12941cad7ea6SRicardo Labiaga int 12951cad7ea6SRicardo Labiaga svc_process(struct svc_rqst *rqstp) 12961cad7ea6SRicardo Labiaga { 12971cad7ea6SRicardo Labiaga struct kvec *argv = &rqstp->rq_arg.head[0]; 12981cad7ea6SRicardo Labiaga struct kvec *resv = &rqstp->rq_res.head[0]; 12991cad7ea6SRicardo Labiaga struct svc_serv *serv = rqstp->rq_server; 13001cad7ea6SRicardo Labiaga u32 dir; 13011cad7ea6SRicardo Labiaga 13021cad7ea6SRicardo Labiaga /* 13031cad7ea6SRicardo Labiaga * Setup response xdr_buf. 13041cad7ea6SRicardo Labiaga * Initially it has just one page 13051cad7ea6SRicardo Labiaga */ 1306afc59400SJ. Bruce Fields rqstp->rq_next_page = &rqstp->rq_respages[1]; 13071cad7ea6SRicardo Labiaga resv->iov_base = page_address(rqstp->rq_respages[0]); 13081cad7ea6SRicardo Labiaga resv->iov_len = 0; 13091cad7ea6SRicardo Labiaga rqstp->rq_res.pages = rqstp->rq_respages + 1; 13101cad7ea6SRicardo Labiaga rqstp->rq_res.len = 0; 13111cad7ea6SRicardo Labiaga rqstp->rq_res.page_base = 0; 13121cad7ea6SRicardo Labiaga rqstp->rq_res.page_len = 0; 13131cad7ea6SRicardo Labiaga rqstp->rq_res.buflen = PAGE_SIZE; 13141cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_base = NULL; 13151cad7ea6SRicardo Labiaga rqstp->rq_res.tail[0].iov_len = 0; 13161cad7ea6SRicardo Labiaga 13171cad7ea6SRicardo Labiaga dir = svc_getnl(argv); 13181cad7ea6SRicardo Labiaga if (dir != 0) { 13191cad7ea6SRicardo Labiaga /* direction != CALL */ 13201cad7ea6SRicardo Labiaga svc_printk(rqstp, "bad direction %d, dropping request\n", dir); 13211cad7ea6SRicardo Labiaga serv->sv_stats->rpcbadfmt++; 1322860a0d9eSJeff Layton goto out_drop; 13231cad7ea6SRicardo Labiaga } 13241cad7ea6SRicardo Labiaga 13254b5b3ba1SAndy Adamson /* Returns 1 for send, 0 for drop */ 1326860a0d9eSJeff Layton if (likely(svc_process_common(rqstp, argv, resv))) { 1327860a0d9eSJeff Layton int ret = svc_send(rqstp); 1328860a0d9eSJeff Layton 1329860a0d9eSJeff Layton trace_svc_process(rqstp, ret); 1330860a0d9eSJeff Layton return ret; 1331860a0d9eSJeff Layton } 1332860a0d9eSJeff Layton out_drop: 1333860a0d9eSJeff Layton trace_svc_process(rqstp, 0); 13344b5b3ba1SAndy Adamson svc_drop(rqstp); 13354b5b3ba1SAndy Adamson return 0; 13364b5b3ba1SAndy Adamson } 13373f87d5d6SChuck Lever EXPORT_SYMBOL_GPL(svc_process); 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]; 1350632dda83SChuck Lever struct rpc_task *task; 13510d2a970dSTrond Myklebust int proc_error; 1352632dda83SChuck Lever int error; 1353632dda83SChuck Lever 1354632dda83SChuck Lever dprintk("svc: %s(%p)\n", __func__, req); 13554d6bbb62SRicardo Labiaga 13564d6bbb62SRicardo Labiaga /* Build the svc_rqst used by the common processing routine */ 13574a19de0fSAndy Adamson rqstp->rq_xprt = serv->sv_bc_xprt; 13584d6bbb62SRicardo Labiaga rqstp->rq_xid = req->rq_xid; 13594d6bbb62SRicardo Labiaga rqstp->rq_prot = req->rq_xprt->prot; 13604d6bbb62SRicardo Labiaga rqstp->rq_server = serv; 13614d6bbb62SRicardo Labiaga 13624d6bbb62SRicardo Labiaga rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); 13634d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); 13644d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); 13654d6bbb62SRicardo Labiaga memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); 13664d6bbb62SRicardo Labiaga 13674d6bbb62SRicardo Labiaga /* reset result send buffer "put" position */ 13684d6bbb62SRicardo Labiaga resv->iov_len = 0; 13694d6bbb62SRicardo Labiaga 13704d6bbb62SRicardo Labiaga /* 13714d6bbb62SRicardo Labiaga * Skip the next two words because they've already been 1372632dda83SChuck Lever * processed in the transport 13734d6bbb62SRicardo Labiaga */ 13744d6bbb62SRicardo Labiaga svc_getu32(argv); /* XID */ 13754d6bbb62SRicardo Labiaga svc_getnl(argv); /* CALLDIR */ 13764d6bbb62SRicardo Labiaga 1377632dda83SChuck Lever /* Parse and execute the bc call */ 13780d2a970dSTrond Myklebust proc_error = svc_process_common(rqstp, argv, resv); 13790d2a970dSTrond Myklebust 13800d2a970dSTrond Myklebust atomic_inc(&req->rq_xprt->bc_free_slots); 13810d2a970dSTrond Myklebust if (!proc_error) { 1382632dda83SChuck Lever /* Processing error: drop the request */ 1383b3b02ae5STrond Myklebust xprt_free_bc_request(req); 13844b5b3ba1SAndy Adamson return 0; 13854b5b3ba1SAndy Adamson } 1386632dda83SChuck Lever 1387632dda83SChuck Lever /* Finally, send the reply synchronously */ 1388632dda83SChuck Lever memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); 13890f419791STrond Myklebust task = rpc_run_bc_task(req); 1390632dda83SChuck Lever if (IS_ERR(task)) { 1391632dda83SChuck Lever error = PTR_ERR(task); 1392632dda83SChuck Lever goto out; 1393632dda83SChuck Lever } 1394632dda83SChuck Lever 1395632dda83SChuck Lever WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); 1396632dda83SChuck Lever error = task->tk_status; 1397632dda83SChuck Lever rpc_put_task(task); 1398632dda83SChuck Lever 1399632dda83SChuck Lever out: 1400632dda83SChuck Lever dprintk("svc: %s(), error=%d\n", __func__, error); 1401632dda83SChuck Lever return error; 14024d6bbb62SRicardo Labiaga } 14030d961aa9STrond Myklebust EXPORT_SYMBOL_GPL(bc_svc_process); 14049e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */ 14054d6bbb62SRicardo Labiaga 14061cad7ea6SRicardo Labiaga /* 14077adae489SGreg Banks * Return (transport-specific) limit on the rpc payload. 14087adae489SGreg Banks */ 14097adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp) 14107adae489SGreg Banks { 141149023155STom Tucker u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload; 14127adae489SGreg Banks 1413c6b0a9f8SNeilBrown if (rqstp->rq_server->sv_max_payload < max) 1414c6b0a9f8SNeilBrown max = rqstp->rq_server->sv_max_payload; 14157adae489SGreg Banks return max; 14167adae489SGreg Banks } 14177adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload); 1418