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> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/sunrpc/types.h> 241da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h> 251da177e4SLinus Torvalds #include <linux/sunrpc/stats.h> 261da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h> 271da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #define RPCDBG_FACILITY RPCDBG_SVCDSP 301da177e4SLinus Torvalds 317252d575SChuck Lever static void svc_unregister(const struct svc_serv *serv); 327252d575SChuck Lever 3342a7fc4aSGreg Banks #define svc_serv_is_pooled(serv) ((serv)->sv_function) 3442a7fc4aSGreg Banks 351da177e4SLinus Torvalds /* 36bfd24160SGreg Banks * Mode for mapping cpus to pools. 37bfd24160SGreg Banks */ 38bfd24160SGreg Banks enum { 3942a7fc4aSGreg Banks SVC_POOL_AUTO = -1, /* choose one of the others */ 40bfd24160SGreg Banks SVC_POOL_GLOBAL, /* no mapping, just a single global pool 41bfd24160SGreg Banks * (legacy & UP mode) */ 42bfd24160SGreg Banks SVC_POOL_PERCPU, /* one pool per cpu */ 43bfd24160SGreg Banks SVC_POOL_PERNODE /* one pool per numa node */ 44bfd24160SGreg Banks }; 4542a7fc4aSGreg Banks #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL 46bfd24160SGreg Banks 47bfd24160SGreg Banks /* 48bfd24160SGreg Banks * Structure for mapping cpus to pools and vice versa. 49bfd24160SGreg Banks * Setup once during sunrpc initialisation. 50bfd24160SGreg Banks */ 51bfd24160SGreg Banks static struct svc_pool_map { 5242a7fc4aSGreg Banks int count; /* How many svc_servs use us */ 53bfd24160SGreg Banks int mode; /* Note: int not enum to avoid 54bfd24160SGreg Banks * warnings about "enumeration value 55bfd24160SGreg Banks * not handled in switch" */ 56bfd24160SGreg Banks unsigned int npools; 57bfd24160SGreg Banks unsigned int *pool_to; /* maps pool id to cpu or node */ 58bfd24160SGreg Banks unsigned int *to_pool; /* maps cpu or node to pool id */ 59bfd24160SGreg Banks } svc_pool_map = { 6042a7fc4aSGreg Banks .count = 0, 6142a7fc4aSGreg Banks .mode = SVC_POOL_DEFAULT 62bfd24160SGreg Banks }; 6342a7fc4aSGreg Banks static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ 64bfd24160SGreg Banks 6542a7fc4aSGreg Banks static int 6642a7fc4aSGreg Banks param_set_pool_mode(const char *val, struct kernel_param *kp) 6742a7fc4aSGreg Banks { 6842a7fc4aSGreg Banks int *ip = (int *)kp->arg; 6942a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 7042a7fc4aSGreg Banks int err; 7142a7fc4aSGreg Banks 7242a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 7342a7fc4aSGreg Banks 7442a7fc4aSGreg Banks err = -EBUSY; 7542a7fc4aSGreg Banks if (m->count) 7642a7fc4aSGreg Banks goto out; 7742a7fc4aSGreg Banks 7842a7fc4aSGreg Banks err = 0; 7942a7fc4aSGreg Banks if (!strncmp(val, "auto", 4)) 8042a7fc4aSGreg Banks *ip = SVC_POOL_AUTO; 8142a7fc4aSGreg Banks else if (!strncmp(val, "global", 6)) 8242a7fc4aSGreg Banks *ip = SVC_POOL_GLOBAL; 8342a7fc4aSGreg Banks else if (!strncmp(val, "percpu", 6)) 8442a7fc4aSGreg Banks *ip = SVC_POOL_PERCPU; 8542a7fc4aSGreg Banks else if (!strncmp(val, "pernode", 7)) 8642a7fc4aSGreg Banks *ip = SVC_POOL_PERNODE; 8742a7fc4aSGreg Banks else 8842a7fc4aSGreg Banks err = -EINVAL; 8942a7fc4aSGreg Banks 9042a7fc4aSGreg Banks out: 9142a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 9242a7fc4aSGreg Banks return err; 9342a7fc4aSGreg Banks } 9442a7fc4aSGreg Banks 9542a7fc4aSGreg Banks static int 9642a7fc4aSGreg Banks param_get_pool_mode(char *buf, struct kernel_param *kp) 9742a7fc4aSGreg Banks { 9842a7fc4aSGreg Banks int *ip = (int *)kp->arg; 9942a7fc4aSGreg Banks 10042a7fc4aSGreg Banks switch (*ip) 10142a7fc4aSGreg Banks { 10242a7fc4aSGreg Banks case SVC_POOL_AUTO: 10342a7fc4aSGreg Banks return strlcpy(buf, "auto", 20); 10442a7fc4aSGreg Banks case SVC_POOL_GLOBAL: 10542a7fc4aSGreg Banks return strlcpy(buf, "global", 20); 10642a7fc4aSGreg Banks case SVC_POOL_PERCPU: 10742a7fc4aSGreg Banks return strlcpy(buf, "percpu", 20); 10842a7fc4aSGreg Banks case SVC_POOL_PERNODE: 10942a7fc4aSGreg Banks return strlcpy(buf, "pernode", 20); 11042a7fc4aSGreg Banks default: 11142a7fc4aSGreg Banks return sprintf(buf, "%d", *ip); 11242a7fc4aSGreg Banks } 11342a7fc4aSGreg Banks } 11442a7fc4aSGreg Banks 11542a7fc4aSGreg Banks module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode, 11642a7fc4aSGreg Banks &svc_pool_map.mode, 0644); 117bfd24160SGreg Banks 118bfd24160SGreg Banks /* 119bfd24160SGreg Banks * Detect best pool mapping mode heuristically, 120bfd24160SGreg Banks * according to the machine's topology. 121bfd24160SGreg Banks */ 122bfd24160SGreg Banks static int 123bfd24160SGreg Banks svc_pool_map_choose_mode(void) 124bfd24160SGreg Banks { 125bfd24160SGreg Banks unsigned int node; 126bfd24160SGreg Banks 127bfd24160SGreg Banks if (num_online_nodes() > 1) { 128bfd24160SGreg Banks /* 129bfd24160SGreg Banks * Actually have multiple NUMA nodes, 130bfd24160SGreg Banks * so split pools on NUMA node boundaries 131bfd24160SGreg Banks */ 132bfd24160SGreg Banks return SVC_POOL_PERNODE; 133bfd24160SGreg Banks } 134bfd24160SGreg Banks 135bfd24160SGreg Banks node = any_online_node(node_online_map); 136bfd24160SGreg Banks if (nr_cpus_node(node) > 2) { 137bfd24160SGreg Banks /* 138bfd24160SGreg Banks * Non-trivial SMP, or CONFIG_NUMA on 139bfd24160SGreg Banks * non-NUMA hardware, e.g. with a generic 140bfd24160SGreg Banks * x86_64 kernel on Xeons. In this case we 141bfd24160SGreg Banks * want to divide the pools on cpu boundaries. 142bfd24160SGreg Banks */ 143bfd24160SGreg Banks return SVC_POOL_PERCPU; 144bfd24160SGreg Banks } 145bfd24160SGreg Banks 146bfd24160SGreg Banks /* default: one global pool */ 147bfd24160SGreg Banks return SVC_POOL_GLOBAL; 148bfd24160SGreg Banks } 149bfd24160SGreg Banks 150bfd24160SGreg Banks /* 151bfd24160SGreg Banks * Allocate the to_pool[] and pool_to[] arrays. 152bfd24160SGreg Banks * Returns 0 on success or an errno. 153bfd24160SGreg Banks */ 154bfd24160SGreg Banks static int 155bfd24160SGreg Banks svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) 156bfd24160SGreg Banks { 157bfd24160SGreg Banks m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 158bfd24160SGreg Banks if (!m->to_pool) 159bfd24160SGreg Banks goto fail; 160bfd24160SGreg Banks m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); 161bfd24160SGreg Banks if (!m->pool_to) 162bfd24160SGreg Banks goto fail_free; 163bfd24160SGreg Banks 164bfd24160SGreg Banks return 0; 165bfd24160SGreg Banks 166bfd24160SGreg Banks fail_free: 167bfd24160SGreg Banks kfree(m->to_pool); 168bfd24160SGreg Banks fail: 169bfd24160SGreg Banks return -ENOMEM; 170bfd24160SGreg Banks } 171bfd24160SGreg Banks 172bfd24160SGreg Banks /* 173bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERCPU mode. 174bfd24160SGreg Banks * Returns number of pools or <0 on error. 175bfd24160SGreg Banks */ 176bfd24160SGreg Banks static int 177bfd24160SGreg Banks svc_pool_map_init_percpu(struct svc_pool_map *m) 178bfd24160SGreg Banks { 17953b8a315SChristoph Lameter unsigned int maxpools = nr_cpu_ids; 180bfd24160SGreg Banks unsigned int pidx = 0; 181bfd24160SGreg Banks unsigned int cpu; 182bfd24160SGreg Banks int err; 183bfd24160SGreg Banks 184bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 185bfd24160SGreg Banks if (err) 186bfd24160SGreg Banks return err; 187bfd24160SGreg Banks 188bfd24160SGreg Banks for_each_online_cpu(cpu) { 189bfd24160SGreg Banks BUG_ON(pidx > maxpools); 190bfd24160SGreg Banks m->to_pool[cpu] = pidx; 191bfd24160SGreg Banks m->pool_to[pidx] = cpu; 192bfd24160SGreg Banks pidx++; 193bfd24160SGreg Banks } 194bfd24160SGreg Banks /* cpus brought online later all get mapped to pool0, sorry */ 195bfd24160SGreg Banks 196bfd24160SGreg Banks return pidx; 197bfd24160SGreg Banks }; 198bfd24160SGreg Banks 199bfd24160SGreg Banks 200bfd24160SGreg Banks /* 201bfd24160SGreg Banks * Initialise the pool map for SVC_POOL_PERNODE mode. 202bfd24160SGreg Banks * Returns number of pools or <0 on error. 203bfd24160SGreg Banks */ 204bfd24160SGreg Banks static int 205bfd24160SGreg Banks svc_pool_map_init_pernode(struct svc_pool_map *m) 206bfd24160SGreg Banks { 20774c7aa8bSChristoph Lameter unsigned int maxpools = nr_node_ids; 208bfd24160SGreg Banks unsigned int pidx = 0; 209bfd24160SGreg Banks unsigned int node; 210bfd24160SGreg Banks int err; 211bfd24160SGreg Banks 212bfd24160SGreg Banks err = svc_pool_map_alloc_arrays(m, maxpools); 213bfd24160SGreg Banks if (err) 214bfd24160SGreg Banks return err; 215bfd24160SGreg Banks 216bfd24160SGreg Banks for_each_node_with_cpus(node) { 217bfd24160SGreg Banks /* some architectures (e.g. SN2) have cpuless nodes */ 218bfd24160SGreg Banks BUG_ON(pidx > maxpools); 219bfd24160SGreg Banks m->to_pool[node] = pidx; 220bfd24160SGreg Banks m->pool_to[pidx] = node; 221bfd24160SGreg Banks pidx++; 222bfd24160SGreg Banks } 223bfd24160SGreg Banks /* nodes brought online later all get mapped to pool0, sorry */ 224bfd24160SGreg Banks 225bfd24160SGreg Banks return pidx; 226bfd24160SGreg Banks } 227bfd24160SGreg Banks 228bfd24160SGreg Banks 229bfd24160SGreg Banks /* 23042a7fc4aSGreg Banks * Add a reference to the global map of cpus to pools (and 23142a7fc4aSGreg Banks * vice versa). Initialise the map if we're the first user. 23242a7fc4aSGreg Banks * Returns the number of pools. 233bfd24160SGreg Banks */ 234bfd24160SGreg Banks static unsigned int 23542a7fc4aSGreg Banks svc_pool_map_get(void) 236bfd24160SGreg Banks { 237bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 238bfd24160SGreg Banks int npools = -1; 239bfd24160SGreg Banks 24042a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 241bfd24160SGreg Banks 24242a7fc4aSGreg Banks if (m->count++) { 24342a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 24442a7fc4aSGreg Banks return m->npools; 24542a7fc4aSGreg Banks } 24642a7fc4aSGreg Banks 24742a7fc4aSGreg Banks if (m->mode == SVC_POOL_AUTO) 248bfd24160SGreg Banks m->mode = svc_pool_map_choose_mode(); 249bfd24160SGreg Banks 250bfd24160SGreg Banks switch (m->mode) { 251bfd24160SGreg Banks case SVC_POOL_PERCPU: 252bfd24160SGreg Banks npools = svc_pool_map_init_percpu(m); 253bfd24160SGreg Banks break; 254bfd24160SGreg Banks case SVC_POOL_PERNODE: 255bfd24160SGreg Banks npools = svc_pool_map_init_pernode(m); 256bfd24160SGreg Banks break; 257bfd24160SGreg Banks } 258bfd24160SGreg Banks 259bfd24160SGreg Banks if (npools < 0) { 260bfd24160SGreg Banks /* default, or memory allocation failure */ 261bfd24160SGreg Banks npools = 1; 262bfd24160SGreg Banks m->mode = SVC_POOL_GLOBAL; 263bfd24160SGreg Banks } 264bfd24160SGreg Banks m->npools = npools; 265bfd24160SGreg Banks 26642a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 267bfd24160SGreg Banks return m->npools; 268bfd24160SGreg Banks } 269bfd24160SGreg Banks 27042a7fc4aSGreg Banks 27142a7fc4aSGreg Banks /* 27242a7fc4aSGreg Banks * Drop a reference to the global map of cpus to pools. 27342a7fc4aSGreg Banks * When the last reference is dropped, the map data is 27442a7fc4aSGreg Banks * freed; this allows the sysadmin to change the pool 27542a7fc4aSGreg Banks * mode using the pool_mode module option without 27642a7fc4aSGreg Banks * rebooting or re-loading sunrpc.ko. 27742a7fc4aSGreg Banks */ 27842a7fc4aSGreg Banks static void 27942a7fc4aSGreg Banks svc_pool_map_put(void) 28042a7fc4aSGreg Banks { 28142a7fc4aSGreg Banks struct svc_pool_map *m = &svc_pool_map; 28242a7fc4aSGreg Banks 28342a7fc4aSGreg Banks mutex_lock(&svc_pool_map_mutex); 28442a7fc4aSGreg Banks 28542a7fc4aSGreg Banks if (!--m->count) { 28642a7fc4aSGreg Banks m->mode = SVC_POOL_DEFAULT; 28742a7fc4aSGreg Banks kfree(m->to_pool); 28842a7fc4aSGreg Banks kfree(m->pool_to); 28942a7fc4aSGreg Banks m->npools = 0; 29042a7fc4aSGreg Banks } 29142a7fc4aSGreg Banks 29242a7fc4aSGreg Banks mutex_unlock(&svc_pool_map_mutex); 29342a7fc4aSGreg Banks } 29442a7fc4aSGreg Banks 29542a7fc4aSGreg Banks 296bfd24160SGreg Banks /* 2979867d76cSJeff Layton * Set the given thread's cpus_allowed mask so that it 298bfd24160SGreg Banks * will only run on cpus in the given pool. 299bfd24160SGreg Banks */ 3009867d76cSJeff Layton static inline void 3019867d76cSJeff Layton svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) 302bfd24160SGreg Banks { 303bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 3049867d76cSJeff Layton unsigned int node = m->pool_to[pidx]; 305bfd24160SGreg Banks 306bfd24160SGreg Banks /* 307bfd24160SGreg Banks * The caller checks for sv_nrpools > 1, which 30842a7fc4aSGreg Banks * implies that we've been initialized. 309bfd24160SGreg Banks */ 31042a7fc4aSGreg Banks BUG_ON(m->count == 0); 311bfd24160SGreg Banks 3129867d76cSJeff Layton switch (m->mode) { 313bfd24160SGreg Banks case SVC_POOL_PERCPU: 314c5f59f08SMike Travis { 3150bc3cc03SMike Travis set_cpus_allowed_ptr(task, &cpumask_of_cpu(node)); 3169867d76cSJeff Layton break; 317c5f59f08SMike Travis } 318bfd24160SGreg Banks case SVC_POOL_PERNODE: 319c5f59f08SMike Travis { 320c5f59f08SMike Travis node_to_cpumask_ptr(nodecpumask, node); 3219867d76cSJeff Layton set_cpus_allowed_ptr(task, nodecpumask); 3229867d76cSJeff Layton break; 323bfd24160SGreg Banks } 324bfd24160SGreg Banks } 325c5f59f08SMike Travis } 326bfd24160SGreg Banks 327bfd24160SGreg Banks /* 328bfd24160SGreg Banks * Use the mapping mode to choose a pool for a given CPU. 329bfd24160SGreg Banks * Used when enqueueing an incoming RPC. Always returns 330bfd24160SGreg Banks * a non-NULL pool pointer. 331bfd24160SGreg Banks */ 332bfd24160SGreg Banks struct svc_pool * 333bfd24160SGreg Banks svc_pool_for_cpu(struct svc_serv *serv, int cpu) 334bfd24160SGreg Banks { 335bfd24160SGreg Banks struct svc_pool_map *m = &svc_pool_map; 336bfd24160SGreg Banks unsigned int pidx = 0; 337bfd24160SGreg Banks 338bfd24160SGreg Banks /* 33942a7fc4aSGreg Banks * An uninitialised map happens in a pure client when 340bfd24160SGreg Banks * lockd is brought up, so silently treat it the 341bfd24160SGreg Banks * same as SVC_POOL_GLOBAL. 342bfd24160SGreg Banks */ 34342a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) { 344bfd24160SGreg Banks switch (m->mode) { 345bfd24160SGreg Banks case SVC_POOL_PERCPU: 346bfd24160SGreg Banks pidx = m->to_pool[cpu]; 347bfd24160SGreg Banks break; 348bfd24160SGreg Banks case SVC_POOL_PERNODE: 349bfd24160SGreg Banks pidx = m->to_pool[cpu_to_node(cpu)]; 350bfd24160SGreg Banks break; 351bfd24160SGreg Banks } 35242a7fc4aSGreg Banks } 353bfd24160SGreg Banks return &serv->sv_pools[pidx % serv->sv_nrpools]; 354bfd24160SGreg Banks } 355bfd24160SGreg Banks 356bfd24160SGreg Banks 357bfd24160SGreg Banks /* 3581da177e4SLinus Torvalds * Create an RPC service 3591da177e4SLinus Torvalds */ 360a7455442SGreg Banks static struct svc_serv * 361a7455442SGreg Banks __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, 362e851db5bSChuck Lever sa_family_t family, void (*shutdown)(struct svc_serv *serv)) 3631da177e4SLinus Torvalds { 3641da177e4SLinus Torvalds struct svc_serv *serv; 365ea339d46SChuck Lever unsigned int vers; 3661da177e4SLinus Torvalds unsigned int xdrsize; 3673262c816SGreg Banks unsigned int i; 3681da177e4SLinus Torvalds 3690da974f4SPanagiotis Issaris if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) 3701da177e4SLinus Torvalds return NULL; 371e851db5bSChuck Lever serv->sv_family = family; 3729ba02638SAndreas Gruenbacher serv->sv_name = prog->pg_name; 3731da177e4SLinus Torvalds serv->sv_program = prog; 3741da177e4SLinus Torvalds serv->sv_nrthreads = 1; 3751da177e4SLinus Torvalds serv->sv_stats = prog->pg_stats; 376c6b0a9f8SNeilBrown if (bufsize > RPCSVC_MAXPAYLOAD) 377c6b0a9f8SNeilBrown bufsize = RPCSVC_MAXPAYLOAD; 378c6b0a9f8SNeilBrown serv->sv_max_payload = bufsize? bufsize : 4096; 379c6b0a9f8SNeilBrown serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); 380bc591ccfSNeilBrown serv->sv_shutdown = shutdown; 3811da177e4SLinus Torvalds xdrsize = 0; 3829ba02638SAndreas Gruenbacher while (prog) { 3839ba02638SAndreas Gruenbacher prog->pg_lovers = prog->pg_nvers-1; 3841da177e4SLinus Torvalds for (vers=0; vers<prog->pg_nvers ; vers++) 3851da177e4SLinus Torvalds if (prog->pg_vers[vers]) { 3861da177e4SLinus Torvalds prog->pg_hivers = vers; 3871da177e4SLinus Torvalds if (prog->pg_lovers > vers) 3881da177e4SLinus Torvalds prog->pg_lovers = vers; 3891da177e4SLinus Torvalds if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) 3901da177e4SLinus Torvalds xdrsize = prog->pg_vers[vers]->vs_xdrsize; 3911da177e4SLinus Torvalds } 3929ba02638SAndreas Gruenbacher prog = prog->pg_next; 3939ba02638SAndreas Gruenbacher } 3941da177e4SLinus Torvalds serv->sv_xdrsize = xdrsize; 3951da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_tempsocks); 3961da177e4SLinus Torvalds INIT_LIST_HEAD(&serv->sv_permsocks); 39736bdfc8bSGreg Banks init_timer(&serv->sv_temptimer); 3981da177e4SLinus Torvalds spin_lock_init(&serv->sv_lock); 3991da177e4SLinus Torvalds 400a7455442SGreg Banks serv->sv_nrpools = npools; 4013262c816SGreg Banks serv->sv_pools = 402cd861280SRobert P. J. Day kcalloc(serv->sv_nrpools, sizeof(struct svc_pool), 4033262c816SGreg Banks GFP_KERNEL); 4043262c816SGreg Banks if (!serv->sv_pools) { 4053262c816SGreg Banks kfree(serv); 4063262c816SGreg Banks return NULL; 4073262c816SGreg Banks } 4083262c816SGreg Banks 4093262c816SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 4103262c816SGreg Banks struct svc_pool *pool = &serv->sv_pools[i]; 4113262c816SGreg Banks 41246121cf7SChuck Lever dprintk("svc: initialising pool %u for %s\n", 4133262c816SGreg Banks i, serv->sv_name); 4143262c816SGreg Banks 4153262c816SGreg Banks pool->sp_id = i; 4163262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_threads); 4173262c816SGreg Banks INIT_LIST_HEAD(&pool->sp_sockets); 418a7455442SGreg Banks INIT_LIST_HEAD(&pool->sp_all_threads); 4193262c816SGreg Banks spin_lock_init(&pool->sp_lock); 4203262c816SGreg Banks } 4213262c816SGreg Banks 4221da177e4SLinus Torvalds /* Remove any stale portmap registrations */ 4237252d575SChuck Lever svc_unregister(serv); 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds return serv; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 428a7455442SGreg Banks struct svc_serv * 429a7455442SGreg Banks svc_create(struct svc_program *prog, unsigned int bufsize, 430e851db5bSChuck Lever sa_family_t family, void (*shutdown)(struct svc_serv *serv)) 431a7455442SGreg Banks { 432e851db5bSChuck Lever return __svc_create(prog, bufsize, /*npools*/1, family, shutdown); 433a7455442SGreg Banks } 434d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_create); 435a7455442SGreg Banks 436a7455442SGreg Banks struct svc_serv * 437a7455442SGreg Banks svc_create_pooled(struct svc_program *prog, unsigned int bufsize, 438e851db5bSChuck Lever sa_family_t family, void (*shutdown)(struct svc_serv *serv), 439a75c5d01SJeff Layton svc_thread_fn func, struct module *mod) 440a7455442SGreg Banks { 441a7455442SGreg Banks struct svc_serv *serv; 44242a7fc4aSGreg Banks unsigned int npools = svc_pool_map_get(); 443a7455442SGreg Banks 444e851db5bSChuck Lever serv = __svc_create(prog, bufsize, npools, family, shutdown); 445a7455442SGreg Banks 446a7455442SGreg Banks if (serv != NULL) { 447a7455442SGreg Banks serv->sv_function = func; 448a7455442SGreg Banks serv->sv_module = mod; 449a7455442SGreg Banks } 450a7455442SGreg Banks 451a7455442SGreg Banks return serv; 452a7455442SGreg Banks } 453d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_create_pooled); 454a7455442SGreg Banks 4551da177e4SLinus Torvalds /* 456bedbdd8bSNeil Brown * Destroy an RPC service. Should be called with appropriate locking to 457bedbdd8bSNeil Brown * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. 4581da177e4SLinus Torvalds */ 4591da177e4SLinus Torvalds void 4601da177e4SLinus Torvalds svc_destroy(struct svc_serv *serv) 4611da177e4SLinus Torvalds { 46246121cf7SChuck Lever dprintk("svc: svc_destroy(%s, %d)\n", 4631da177e4SLinus Torvalds serv->sv_program->pg_name, 4641da177e4SLinus Torvalds serv->sv_nrthreads); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds if (serv->sv_nrthreads) { 4671da177e4SLinus Torvalds if (--(serv->sv_nrthreads) != 0) { 4681da177e4SLinus Torvalds svc_sock_update_bufs(serv); 4691da177e4SLinus Torvalds return; 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds } else 4721da177e4SLinus Torvalds printk("svc_destroy: no threads for serv=%p!\n", serv); 4731da177e4SLinus Torvalds 47436bdfc8bSGreg Banks del_timer_sync(&serv->sv_temptimer); 47536bdfc8bSGreg Banks 4767a182083STom Tucker svc_close_all(&serv->sv_tempsocks); 477cda1fd4aSNeilBrown 478bc591ccfSNeilBrown if (serv->sv_shutdown) 479bc591ccfSNeilBrown serv->sv_shutdown(serv); 480bc591ccfSNeilBrown 4817a182083STom Tucker svc_close_all(&serv->sv_permsocks); 482cda1fd4aSNeilBrown 483cda1fd4aSNeilBrown BUG_ON(!list_empty(&serv->sv_permsocks)); 484cda1fd4aSNeilBrown BUG_ON(!list_empty(&serv->sv_tempsocks)); 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds cache_clean_deferred(serv); 4871da177e4SLinus Torvalds 48842a7fc4aSGreg Banks if (svc_serv_is_pooled(serv)) 48942a7fc4aSGreg Banks svc_pool_map_put(); 49042a7fc4aSGreg Banks 4917252d575SChuck Lever svc_unregister(serv); 4923262c816SGreg Banks kfree(serv->sv_pools); 4931da177e4SLinus Torvalds kfree(serv); 4941da177e4SLinus Torvalds } 495d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_destroy); 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* 4981da177e4SLinus Torvalds * Allocate an RPC server's buffer space. 4991da177e4SLinus Torvalds * We allocate pages and place them in rq_argpages. 5001da177e4SLinus Torvalds */ 5011da177e4SLinus Torvalds static int 5021da177e4SLinus Torvalds svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) 5031da177e4SLinus Torvalds { 5040dc220f0SChuck Lever unsigned int pages, arghi; 5051da177e4SLinus Torvalds 506c6b0a9f8SNeilBrown pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. 507c6b0a9f8SNeilBrown * We assume one is at most one page 508c6b0a9f8SNeilBrown */ 5091da177e4SLinus Torvalds arghi = 0; 51009a62660SKris Katterjohn BUG_ON(pages > RPCSVC_MAXPAGES); 5111da177e4SLinus Torvalds while (pages) { 5121da177e4SLinus Torvalds struct page *p = alloc_page(GFP_KERNEL); 5131da177e4SLinus Torvalds if (!p) 5141da177e4SLinus Torvalds break; 51544524359SNeilBrown rqstp->rq_pages[arghi++] = p; 5161da177e4SLinus Torvalds pages--; 5171da177e4SLinus Torvalds } 5180dc220f0SChuck Lever return pages == 0; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds /* 5221da177e4SLinus Torvalds * Release an RPC server buffer 5231da177e4SLinus Torvalds */ 5241da177e4SLinus Torvalds static void 5251da177e4SLinus Torvalds svc_release_buffer(struct svc_rqst *rqstp) 5261da177e4SLinus Torvalds { 52750c8bb13SChuck Lever unsigned int i; 52850c8bb13SChuck Lever 52944524359SNeilBrown for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) 53044524359SNeilBrown if (rqstp->rq_pages[i]) 53144524359SNeilBrown put_page(rqstp->rq_pages[i]); 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5340113ab34SJeff Layton struct svc_rqst * 5350113ab34SJeff Layton svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool) 5360113ab34SJeff Layton { 5370113ab34SJeff Layton struct svc_rqst *rqstp; 5380113ab34SJeff Layton 5390113ab34SJeff Layton rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); 5400113ab34SJeff Layton if (!rqstp) 5410113ab34SJeff Layton goto out_enomem; 5420113ab34SJeff Layton 5430113ab34SJeff Layton init_waitqueue_head(&rqstp->rq_wait); 5440113ab34SJeff Layton 5450113ab34SJeff Layton serv->sv_nrthreads++; 5460113ab34SJeff Layton spin_lock_bh(&pool->sp_lock); 5470113ab34SJeff Layton pool->sp_nrthreads++; 5480113ab34SJeff Layton list_add(&rqstp->rq_all, &pool->sp_all_threads); 5490113ab34SJeff Layton spin_unlock_bh(&pool->sp_lock); 5500113ab34SJeff Layton rqstp->rq_server = serv; 5510113ab34SJeff Layton rqstp->rq_pool = pool; 5520113ab34SJeff Layton 5530113ab34SJeff Layton rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); 5540113ab34SJeff Layton if (!rqstp->rq_argp) 5550113ab34SJeff Layton goto out_thread; 5560113ab34SJeff Layton 5570113ab34SJeff Layton rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); 5580113ab34SJeff Layton if (!rqstp->rq_resp) 5590113ab34SJeff Layton goto out_thread; 5600113ab34SJeff Layton 5610113ab34SJeff Layton if (!svc_init_buffer(rqstp, serv->sv_max_mesg)) 5620113ab34SJeff Layton goto out_thread; 5630113ab34SJeff Layton 5640113ab34SJeff Layton return rqstp; 5650113ab34SJeff Layton out_thread: 5660113ab34SJeff Layton svc_exit_thread(rqstp); 5670113ab34SJeff Layton out_enomem: 5680113ab34SJeff Layton return ERR_PTR(-ENOMEM); 5690113ab34SJeff Layton } 5700113ab34SJeff Layton EXPORT_SYMBOL(svc_prepare_thread); 5710113ab34SJeff Layton 5721da177e4SLinus Torvalds /* 573a7455442SGreg Banks * Choose a pool in which to create a new thread, for svc_set_num_threads 574a7455442SGreg Banks */ 575a7455442SGreg Banks static inline struct svc_pool * 576a7455442SGreg Banks choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 577a7455442SGreg Banks { 578a7455442SGreg Banks if (pool != NULL) 579a7455442SGreg Banks return pool; 580a7455442SGreg Banks 581a7455442SGreg Banks return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; 582a7455442SGreg Banks } 583a7455442SGreg Banks 584a7455442SGreg Banks /* 585a7455442SGreg Banks * Choose a thread to kill, for svc_set_num_threads 586a7455442SGreg Banks */ 587a7455442SGreg Banks static inline struct task_struct * 588a7455442SGreg Banks choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) 589a7455442SGreg Banks { 590a7455442SGreg Banks unsigned int i; 591a7455442SGreg Banks struct task_struct *task = NULL; 592a7455442SGreg Banks 593a7455442SGreg Banks if (pool != NULL) { 594a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 595a7455442SGreg Banks } else { 596a7455442SGreg Banks /* choose a pool in round-robin fashion */ 597a7455442SGreg Banks for (i = 0; i < serv->sv_nrpools; i++) { 598a7455442SGreg Banks pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; 599a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 600a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) 601a7455442SGreg Banks goto found_pool; 602a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 603a7455442SGreg Banks } 604a7455442SGreg Banks return NULL; 605a7455442SGreg Banks } 606a7455442SGreg Banks 607a7455442SGreg Banks found_pool: 608a7455442SGreg Banks if (!list_empty(&pool->sp_all_threads)) { 609a7455442SGreg Banks struct svc_rqst *rqstp; 610a7455442SGreg Banks 611a7455442SGreg Banks /* 612a7455442SGreg Banks * Remove from the pool->sp_all_threads list 613a7455442SGreg Banks * so we don't try to kill it again. 614a7455442SGreg Banks */ 615a7455442SGreg Banks rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); 616a7455442SGreg Banks list_del_init(&rqstp->rq_all); 617a7455442SGreg Banks task = rqstp->rq_task; 618a7455442SGreg Banks } 619a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 620a7455442SGreg Banks 621a7455442SGreg Banks return task; 622a7455442SGreg Banks } 623a7455442SGreg Banks 624a7455442SGreg Banks /* 625a7455442SGreg Banks * Create or destroy enough new threads to make the number 626a7455442SGreg Banks * of threads the given number. If `pool' is non-NULL, applies 627a7455442SGreg Banks * only to threads in that pool, otherwise round-robins between 628a7455442SGreg Banks * all pools. Must be called with a svc_get() reference and 629bedbdd8bSNeil Brown * the BKL or another lock to protect access to svc_serv fields. 630a7455442SGreg Banks * 631a7455442SGreg Banks * Destroying threads relies on the service threads filling in 632a7455442SGreg Banks * rqstp->rq_task, which only the nfs ones do. Assumes the serv 633a7455442SGreg Banks * has been created using svc_create_pooled(). 634a7455442SGreg Banks * 635a7455442SGreg Banks * Based on code that used to be in nfsd_svc() but tweaked 636a7455442SGreg Banks * to be pool-aware. 637a7455442SGreg Banks */ 638a7455442SGreg Banks int 639a7455442SGreg Banks svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) 640a7455442SGreg Banks { 6419867d76cSJeff Layton struct svc_rqst *rqstp; 6429867d76cSJeff Layton struct task_struct *task; 6439867d76cSJeff Layton struct svc_pool *chosen_pool; 644a7455442SGreg Banks int error = 0; 645a7455442SGreg Banks unsigned int state = serv->sv_nrthreads-1; 646a7455442SGreg Banks 647a7455442SGreg Banks if (pool == NULL) { 648a7455442SGreg Banks /* The -1 assumes caller has done a svc_get() */ 649a7455442SGreg Banks nrservs -= (serv->sv_nrthreads-1); 650a7455442SGreg Banks } else { 651a7455442SGreg Banks spin_lock_bh(&pool->sp_lock); 652a7455442SGreg Banks nrservs -= pool->sp_nrthreads; 653a7455442SGreg Banks spin_unlock_bh(&pool->sp_lock); 654a7455442SGreg Banks } 655a7455442SGreg Banks 656a7455442SGreg Banks /* create new threads */ 657a7455442SGreg Banks while (nrservs > 0) { 658a7455442SGreg Banks nrservs--; 6599867d76cSJeff Layton chosen_pool = choose_pool(serv, pool, &state); 6609867d76cSJeff Layton 6619867d76cSJeff Layton rqstp = svc_prepare_thread(serv, chosen_pool); 6629867d76cSJeff Layton if (IS_ERR(rqstp)) { 6639867d76cSJeff Layton error = PTR_ERR(rqstp); 664a7455442SGreg Banks break; 665a7455442SGreg Banks } 6669867d76cSJeff Layton 6679867d76cSJeff Layton __module_get(serv->sv_module); 6689867d76cSJeff Layton task = kthread_create(serv->sv_function, rqstp, serv->sv_name); 6699867d76cSJeff Layton if (IS_ERR(task)) { 6709867d76cSJeff Layton error = PTR_ERR(task); 6719867d76cSJeff Layton module_put(serv->sv_module); 6729867d76cSJeff Layton svc_exit_thread(rqstp); 6739867d76cSJeff Layton break; 6749867d76cSJeff Layton } 6759867d76cSJeff Layton 6769867d76cSJeff Layton rqstp->rq_task = task; 6779867d76cSJeff Layton if (serv->sv_nrpools > 1) 6789867d76cSJeff Layton svc_pool_map_set_cpumask(task, chosen_pool->sp_id); 6799867d76cSJeff Layton 6809867d76cSJeff Layton svc_sock_update_bufs(serv); 6819867d76cSJeff Layton wake_up_process(task); 682a7455442SGreg Banks } 683a7455442SGreg Banks /* destroy old threads */ 684a7455442SGreg Banks while (nrservs < 0 && 6859867d76cSJeff Layton (task = choose_victim(serv, pool, &state)) != NULL) { 686a75c5d01SJeff Layton send_sig(SIGINT, task, 1); 687a7455442SGreg Banks nrservs++; 688a7455442SGreg Banks } 689a7455442SGreg Banks 690a7455442SGreg Banks return error; 691a7455442SGreg Banks } 692d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_set_num_threads); 693a7455442SGreg Banks 694a7455442SGreg Banks /* 695bedbdd8bSNeil Brown * Called from a server thread as it's exiting. Caller must hold the BKL or 696bedbdd8bSNeil Brown * the "service mutex", whichever is appropriate for the service. 6971da177e4SLinus Torvalds */ 6981da177e4SLinus Torvalds void 6991da177e4SLinus Torvalds svc_exit_thread(struct svc_rqst *rqstp) 7001da177e4SLinus Torvalds { 7011da177e4SLinus Torvalds struct svc_serv *serv = rqstp->rq_server; 7023262c816SGreg Banks struct svc_pool *pool = rqstp->rq_pool; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds svc_release_buffer(rqstp); 7051da177e4SLinus Torvalds kfree(rqstp->rq_resp); 7061da177e4SLinus Torvalds kfree(rqstp->rq_argp); 7071da177e4SLinus Torvalds kfree(rqstp->rq_auth_data); 7083262c816SGreg Banks 7093262c816SGreg Banks spin_lock_bh(&pool->sp_lock); 7103262c816SGreg Banks pool->sp_nrthreads--; 711a7455442SGreg Banks list_del(&rqstp->rq_all); 7123262c816SGreg Banks spin_unlock_bh(&pool->sp_lock); 7133262c816SGreg Banks 7141da177e4SLinus Torvalds kfree(rqstp); 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds /* Release the server */ 7171da177e4SLinus Torvalds if (serv) 7181da177e4SLinus Torvalds svc_destroy(serv); 7191da177e4SLinus Torvalds } 720d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_exit_thread); 7211da177e4SLinus Torvalds 722*a26cfad6SChuck Lever #ifdef CONFIG_SUNRPC_REGISTER_V4 7231da177e4SLinus Torvalds /* 724*a26cfad6SChuck Lever * Registering kernel RPC services with rpcbind version 2 will work 725*a26cfad6SChuck Lever * over either IPv4 or IPv6, since the Linux kernel always registers 726*a26cfad6SChuck Lever * services for the "any" address. 727*a26cfad6SChuck Lever * 728*a26cfad6SChuck Lever * However, the local rpcbind daemon listens on either only AF_INET 729*a26cfad6SChuck Lever * or AF_INET6 (never both). When it listens on AF_INET6, an rpcbind 730*a26cfad6SChuck Lever * version 2 registration will result in registering the service at 731*a26cfad6SChuck Lever * IN6ADDR_ANY, even if the RPC service being registered is not 732*a26cfad6SChuck Lever * IPv6-enabled. 733*a26cfad6SChuck Lever * 734*a26cfad6SChuck Lever * Rpcbind version 4 allows us to be a little more specific. Kernel 735*a26cfad6SChuck Lever * RPC services that don't yet support AF_INET6 can register 736*a26cfad6SChuck Lever * themselves as IPv4-only with the local rpcbind daemon, even if the 737*a26cfad6SChuck Lever * daemon is listening only on AF_INET6. 738*a26cfad6SChuck Lever * 739*a26cfad6SChuck Lever * And, registering IPv6-enabled kernel RPC services via AF_INET6 740*a26cfad6SChuck Lever * verifies that the local user space rpcbind daemon is properly 741*a26cfad6SChuck Lever * configured to support remote AF_INET6 rpcbind requests. 742*a26cfad6SChuck Lever * 743*a26cfad6SChuck Lever * An AF_INET6 registration request will fail if the local rpcbind 744*a26cfad6SChuck Lever * daemon is not set up to listen on AF_INET6. Likewise, we fail 745*a26cfad6SChuck Lever * AF_INET6 registration requests if svc_register() is configured to 746*a26cfad6SChuck Lever * support only rpcbind version 2. 7471da177e4SLinus Torvalds */ 748*a26cfad6SChuck Lever static int __svc_register(const u32 program, const u32 version, 749*a26cfad6SChuck Lever const sa_family_t family, 750*a26cfad6SChuck Lever const unsigned short protocol, 751*a26cfad6SChuck Lever const unsigned short port) 752*a26cfad6SChuck Lever { 753*a26cfad6SChuck Lever struct sockaddr_in sin = { 754*a26cfad6SChuck Lever .sin_family = AF_INET, 755*a26cfad6SChuck Lever .sin_addr.s_addr = htonl(INADDR_ANY), 756*a26cfad6SChuck Lever .sin_port = htons(port), 757*a26cfad6SChuck Lever }; 758*a26cfad6SChuck Lever struct sockaddr_in6 sin6 = { 759*a26cfad6SChuck Lever .sin6_family = AF_INET6, 760*a26cfad6SChuck Lever .sin6_addr = IN6ADDR_ANY_INIT, 761*a26cfad6SChuck Lever .sin6_port = htons(port), 762*a26cfad6SChuck Lever }; 763*a26cfad6SChuck Lever struct sockaddr *sap; 764*a26cfad6SChuck Lever char *netid; 765*a26cfad6SChuck Lever 766*a26cfad6SChuck Lever switch (family) { 767*a26cfad6SChuck Lever case AF_INET: 768*a26cfad6SChuck Lever sap = (struct sockaddr *)&sin; 769*a26cfad6SChuck Lever netid = RPCBIND_NETID_TCP; 770*a26cfad6SChuck Lever if (protocol == IPPROTO_UDP) 771*a26cfad6SChuck Lever netid = RPCBIND_NETID_UDP; 772*a26cfad6SChuck Lever break; 773*a26cfad6SChuck Lever case AF_INET6: 774*a26cfad6SChuck Lever sap = (struct sockaddr *)&sin6; 775*a26cfad6SChuck Lever netid = RPCBIND_NETID_TCP6; 776*a26cfad6SChuck Lever if (protocol == IPPROTO_UDP) 777*a26cfad6SChuck Lever netid = RPCBIND_NETID_UDP6; 778*a26cfad6SChuck Lever break; 779*a26cfad6SChuck Lever default: 780*a26cfad6SChuck Lever return -EAFNOSUPPORT; 781*a26cfad6SChuck Lever } 782*a26cfad6SChuck Lever 783*a26cfad6SChuck Lever return rpcb_v4_register(program, version, sap, netid); 784*a26cfad6SChuck Lever } 785*a26cfad6SChuck Lever #else 786*a26cfad6SChuck Lever static int __svc_register(const u32 program, const u32 version, 787*a26cfad6SChuck Lever sa_family_t family, 788*a26cfad6SChuck Lever const unsigned short protocol, 789*a26cfad6SChuck Lever const unsigned short port) 790*a26cfad6SChuck Lever { 791*a26cfad6SChuck Lever if (family != AF_INET) 792*a26cfad6SChuck Lever return -EAFNOSUPPORT; 793*a26cfad6SChuck Lever 794*a26cfad6SChuck Lever return rpcb_register(program, version, protocol, port); 795*a26cfad6SChuck Lever } 796*a26cfad6SChuck Lever #endif 797*a26cfad6SChuck Lever 798*a26cfad6SChuck Lever /** 799*a26cfad6SChuck Lever * svc_register - register an RPC service with the local portmapper 800*a26cfad6SChuck Lever * @serv: svc_serv struct for the service to register 801*a26cfad6SChuck Lever * @proto: transport protocol number to advertise 802*a26cfad6SChuck Lever * @port: port to advertise 803*a26cfad6SChuck Lever * 804*a26cfad6SChuck Lever * Service is registered for any address in serv's address family 805*a26cfad6SChuck Lever */ 806*a26cfad6SChuck Lever int svc_register(const struct svc_serv *serv, const unsigned short proto, 807*a26cfad6SChuck Lever const unsigned short port) 8081da177e4SLinus Torvalds { 8091da177e4SLinus Torvalds struct svc_program *progp; 810ea339d46SChuck Lever unsigned int i; 81114aeb211SChuck Lever int error = 0; 8121da177e4SLinus Torvalds 8137252d575SChuck Lever BUG_ON(proto == 0 && port == 0); 8141da177e4SLinus Torvalds 815bc5fea42SOlaf Kirch for (progp = serv->sv_program; progp; progp = progp->pg_next) { 8161da177e4SLinus Torvalds for (i = 0; i < progp->pg_nvers; i++) { 8171da177e4SLinus Torvalds if (progp->pg_vers[i] == NULL) 8181da177e4SLinus Torvalds continue; 819bc5fea42SOlaf Kirch 820*a26cfad6SChuck Lever dprintk("svc: svc_register(%s, %u, %s, %u, %d)%s\n", 821bc5fea42SOlaf Kirch progp->pg_name, 822*a26cfad6SChuck Lever serv->sv_family, 823bc5fea42SOlaf Kirch proto == IPPROTO_UDP? "udp" : "tcp", 824bc5fea42SOlaf Kirch port, 825bc5fea42SOlaf Kirch i, 826bc5fea42SOlaf Kirch progp->pg_vers[i]->vs_hidden? 827bc5fea42SOlaf Kirch " (but not telling portmap)" : ""); 828bc5fea42SOlaf Kirch 829bc5fea42SOlaf Kirch if (progp->pg_vers[i]->vs_hidden) 830bc5fea42SOlaf Kirch continue; 831bc5fea42SOlaf Kirch 832*a26cfad6SChuck Lever error = __svc_register(progp->pg_prog, i, 833*a26cfad6SChuck Lever serv->sv_family, proto, port); 8341da177e4SLinus Torvalds if (error < 0) 8351da177e4SLinus Torvalds break; 8361da177e4SLinus Torvalds } 837bc5fea42SOlaf Kirch } 8381da177e4SLinus Torvalds 8397252d575SChuck Lever return error; 8407252d575SChuck Lever } 8417252d575SChuck Lever 8427252d575SChuck Lever /* 8437252d575SChuck Lever * All transport protocols and ports for this service are removed 8447252d575SChuck Lever * from the local rpcbind database if the service is not hidden. 8457252d575SChuck Lever * 8467252d575SChuck Lever * The result of unregistration is reported via dprintk for those 8477252d575SChuck Lever * who want verification of the result, but is otherwise not 8487252d575SChuck Lever * important. 8497252d575SChuck Lever * 8507252d575SChuck Lever * The local rpcbind daemon listens on either only IPv6 or only 8517252d575SChuck Lever * IPv4. The kernel can't tell how it's configured. However, 8527252d575SChuck Lever * AF_INET addresses are mapped to AF_INET6 in IPv6-only config- 8537252d575SChuck Lever * urations, so even an unregistration request on AF_INET will 8547252d575SChuck Lever * get to a local rpcbind daemon listening only on AF_INET6. So 8557252d575SChuck Lever * we always unregister via AF_INET. 8567252d575SChuck Lever * 8577252d575SChuck Lever * At this point we don't need rpcbind version 4 for unregis- 8587252d575SChuck Lever * tration: A v2 UNSET request will clear all transports (netids), 8597252d575SChuck Lever * addresses, and address families for [program, version]. 8607252d575SChuck Lever */ 8617252d575SChuck Lever static void svc_unregister(const struct svc_serv *serv) 8627252d575SChuck Lever { 8637252d575SChuck Lever struct svc_program *progp; 8647252d575SChuck Lever unsigned long flags; 8657252d575SChuck Lever unsigned int i; 8667252d575SChuck Lever int error; 8677252d575SChuck Lever 8687252d575SChuck Lever clear_thread_flag(TIF_SIGPENDING); 8697252d575SChuck Lever 8707252d575SChuck Lever for (progp = serv->sv_program; progp; progp = progp->pg_next) { 8717252d575SChuck Lever for (i = 0; i < progp->pg_nvers; i++) { 8727252d575SChuck Lever if (progp->pg_vers[i] == NULL) 8737252d575SChuck Lever continue; 8747252d575SChuck Lever if (progp->pg_vers[i]->vs_hidden) 8757252d575SChuck Lever continue; 8767252d575SChuck Lever 8777252d575SChuck Lever error = rpcb_register(progp->pg_prog, i, 0, 0); 8787252d575SChuck Lever dprintk("svc: svc_unregister(%sv%u), error %d\n", 8797252d575SChuck Lever progp->pg_name, i, error); 8807252d575SChuck Lever } 8817252d575SChuck Lever } 8827252d575SChuck Lever 8831da177e4SLinus Torvalds spin_lock_irqsave(¤t->sighand->siglock, flags); 8841da177e4SLinus Torvalds recalc_sigpending(); 8851da177e4SLinus Torvalds spin_unlock_irqrestore(¤t->sighand->siglock, flags); 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 8881da177e4SLinus Torvalds /* 889354ecbb9SDr. David Alan Gilbert * Printk the given error with the address of the client that caused it. 890354ecbb9SDr. David Alan Gilbert */ 891354ecbb9SDr. David Alan Gilbert static int 892354ecbb9SDr. David Alan Gilbert __attribute__ ((format (printf, 2, 3))) 893354ecbb9SDr. David Alan Gilbert svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) 894354ecbb9SDr. David Alan Gilbert { 895354ecbb9SDr. David Alan Gilbert va_list args; 896354ecbb9SDr. David Alan Gilbert int r; 897354ecbb9SDr. David Alan Gilbert char buf[RPC_MAX_ADDRBUFLEN]; 898354ecbb9SDr. David Alan Gilbert 899354ecbb9SDr. David Alan Gilbert if (!net_ratelimit()) 900354ecbb9SDr. David Alan Gilbert return 0; 901354ecbb9SDr. David Alan Gilbert 902354ecbb9SDr. David Alan Gilbert printk(KERN_WARNING "svc: %s: ", 903354ecbb9SDr. David Alan Gilbert svc_print_addr(rqstp, buf, sizeof(buf))); 904354ecbb9SDr. David Alan Gilbert 905354ecbb9SDr. David Alan Gilbert va_start(args, fmt); 906354ecbb9SDr. David Alan Gilbert r = vprintk(fmt, args); 907354ecbb9SDr. David Alan Gilbert va_end(args); 908354ecbb9SDr. David Alan Gilbert 909354ecbb9SDr. David Alan Gilbert return r; 910354ecbb9SDr. David Alan Gilbert } 911354ecbb9SDr. David Alan Gilbert 912354ecbb9SDr. David Alan Gilbert /* 9131da177e4SLinus Torvalds * Process the RPC request. 9141da177e4SLinus Torvalds */ 9151da177e4SLinus Torvalds int 9166fb2b47fSNeilBrown svc_process(struct svc_rqst *rqstp) 9171da177e4SLinus Torvalds { 9181da177e4SLinus Torvalds struct svc_program *progp; 9191da177e4SLinus Torvalds struct svc_version *versp = NULL; /* compiler food */ 9201da177e4SLinus Torvalds struct svc_procedure *procp = NULL; 9211da177e4SLinus Torvalds struct kvec * argv = &rqstp->rq_arg.head[0]; 9221da177e4SLinus Torvalds struct kvec * resv = &rqstp->rq_res.head[0]; 9236fb2b47fSNeilBrown struct svc_serv *serv = rqstp->rq_server; 9241da177e4SLinus Torvalds kxdrproc_t xdr; 925d8ed029dSAlexey Dobriyan __be32 *statp; 926d8ed029dSAlexey Dobriyan u32 dir, prog, vers, proc; 927d8ed029dSAlexey Dobriyan __be32 auth_stat, rpc_stat; 9281da177e4SLinus Torvalds int auth_res; 9298f8e05c5SJ.Bruce Fields __be32 *reply_statp; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds rpc_stat = rpc_success; 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds if (argv->iov_len < 6*4) 9341da177e4SLinus Torvalds goto err_short_len; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds /* setup response xdr_buf. 9371da177e4SLinus Torvalds * Initially it has just one page 9381da177e4SLinus Torvalds */ 93944524359SNeilBrown rqstp->rq_resused = 1; 9401da177e4SLinus Torvalds resv->iov_base = page_address(rqstp->rq_respages[0]); 9411da177e4SLinus Torvalds resv->iov_len = 0; 9421da177e4SLinus Torvalds rqstp->rq_res.pages = rqstp->rq_respages + 1; 9431da177e4SLinus Torvalds rqstp->rq_res.len = 0; 9441da177e4SLinus Torvalds rqstp->rq_res.page_base = 0; 9451da177e4SLinus Torvalds rqstp->rq_res.page_len = 0; 946334ccfd5STrond Myklebust rqstp->rq_res.buflen = PAGE_SIZE; 9477c9fdcfbSJ. Bruce Fields rqstp->rq_res.tail[0].iov_base = NULL; 9481da177e4SLinus Torvalds rqstp->rq_res.tail[0].iov_len = 0; 9495c04c46aSJ. Bruce Fields /* Will be turned off only in gss privacy case: */ 950cf8208d0SJens Axboe rqstp->rq_splice_ok = 1; 951e831fe65STom Tucker 952e831fe65STom Tucker /* Setup reply header */ 953e831fe65STom Tucker rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds rqstp->rq_xid = svc_getu32(argv); 9561da177e4SLinus Torvalds svc_putu32(resv, rqstp->rq_xid); 9571da177e4SLinus Torvalds 95876994313SAlexey Dobriyan dir = svc_getnl(argv); 95976994313SAlexey Dobriyan vers = svc_getnl(argv); 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds /* First words of reply: */ 96276994313SAlexey Dobriyan svc_putnl(resv, 1); /* REPLY */ 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds if (dir != 0) /* direction != CALL */ 9651da177e4SLinus Torvalds goto err_bad_dir; 9661da177e4SLinus Torvalds if (vers != 2) /* RPC version number */ 9671da177e4SLinus Torvalds goto err_bad_rpc; 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds /* Save position in case we later decide to reject: */ 9708f8e05c5SJ.Bruce Fields reply_statp = resv->iov_base + resv->iov_len; 9711da177e4SLinus Torvalds 97276994313SAlexey Dobriyan svc_putnl(resv, 0); /* ACCEPT */ 9731da177e4SLinus Torvalds 97476994313SAlexey Dobriyan rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ 97576994313SAlexey Dobriyan rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ 97676994313SAlexey Dobriyan rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds progp = serv->sv_program; 97980d188a6SNeilBrown 98080d188a6SNeilBrown for (progp = serv->sv_program; progp; progp = progp->pg_next) 98180d188a6SNeilBrown if (prog == progp->pg_prog) 98280d188a6SNeilBrown break; 98380d188a6SNeilBrown 9841da177e4SLinus Torvalds /* 9851da177e4SLinus Torvalds * Decode auth data, and add verifier to reply buffer. 9861da177e4SLinus Torvalds * We do this before anything else in order to get a decent 9871da177e4SLinus Torvalds * auth verifier. 9881da177e4SLinus Torvalds */ 9891da177e4SLinus Torvalds auth_res = svc_authenticate(rqstp, &auth_stat); 9901da177e4SLinus Torvalds /* Also give the program a chance to reject this call: */ 99180d188a6SNeilBrown if (auth_res == SVC_OK && progp) { 9921da177e4SLinus Torvalds auth_stat = rpc_autherr_badcred; 9931da177e4SLinus Torvalds auth_res = progp->pg_authenticate(rqstp); 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds switch (auth_res) { 9961da177e4SLinus Torvalds case SVC_OK: 9971da177e4SLinus Torvalds break; 9981da177e4SLinus Torvalds case SVC_GARBAGE: 999dd35210eSHarshula Jayasuriya goto err_garbage; 10001da177e4SLinus Torvalds case SVC_SYSERR: 10011da177e4SLinus Torvalds rpc_stat = rpc_system_err; 10021da177e4SLinus Torvalds goto err_bad; 10031da177e4SLinus Torvalds case SVC_DENIED: 10041da177e4SLinus Torvalds goto err_bad_auth; 10051da177e4SLinus Torvalds case SVC_DROP: 10061da177e4SLinus Torvalds goto dropit; 10071da177e4SLinus Torvalds case SVC_COMPLETE: 10081da177e4SLinus Torvalds goto sendit; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10119ba02638SAndreas Gruenbacher if (progp == NULL) 10121da177e4SLinus Torvalds goto err_bad_prog; 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds if (vers >= progp->pg_nvers || 10151da177e4SLinus Torvalds !(versp = progp->pg_vers[vers])) 10161da177e4SLinus Torvalds goto err_bad_vers; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds procp = versp->vs_proc + proc; 10191da177e4SLinus Torvalds if (proc >= versp->vs_nproc || !procp->pc_func) 10201da177e4SLinus Torvalds goto err_bad_proc; 10211da177e4SLinus Torvalds rqstp->rq_server = serv; 10221da177e4SLinus Torvalds rqstp->rq_procinfo = procp; 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds /* Syntactic check complete */ 10251da177e4SLinus Torvalds serv->sv_stats->rpccnt++; 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds /* Build the reply header. */ 10281da177e4SLinus Torvalds statp = resv->iov_base +resv->iov_len; 102976994313SAlexey Dobriyan svc_putnl(resv, RPC_SUCCESS); 10301da177e4SLinus Torvalds 10311da177e4SLinus Torvalds /* Bump per-procedure stats counter */ 10321da177e4SLinus Torvalds procp->pc_count++; 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds /* Initialize storage for argp and resp */ 10351da177e4SLinus Torvalds memset(rqstp->rq_argp, 0, procp->pc_argsize); 10361da177e4SLinus Torvalds memset(rqstp->rq_resp, 0, procp->pc_ressize); 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds /* un-reserve some of the out-queue now that we have a 10391da177e4SLinus Torvalds * better idea of reply size 10401da177e4SLinus Torvalds */ 10411da177e4SLinus Torvalds if (procp->pc_xdrressize) 1042cd123012SJeff Layton svc_reserve_auth(rqstp, procp->pc_xdrressize<<2); 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds /* Call the function that processes the request. */ 10451da177e4SLinus Torvalds if (!versp->vs_dispatch) { 10461da177e4SLinus Torvalds /* Decode arguments */ 10471da177e4SLinus Torvalds xdr = procp->pc_decode; 10481da177e4SLinus Torvalds if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) 10491da177e4SLinus Torvalds goto err_garbage; 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds /* Encode reply */ 1054d343fce1SNeilBrown if (*statp == rpc_drop_reply) { 1055d343fce1SNeilBrown if (procp->pc_release) 1056d343fce1SNeilBrown procp->pc_release(rqstp, NULL, rqstp->rq_resp); 1057d343fce1SNeilBrown goto dropit; 1058d343fce1SNeilBrown } 10591da177e4SLinus Torvalds if (*statp == rpc_success && (xdr = procp->pc_encode) 10601da177e4SLinus Torvalds && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { 10611da177e4SLinus Torvalds dprintk("svc: failed to encode reply\n"); 10621da177e4SLinus Torvalds /* serv->sv_stats->rpcsystemerr++; */ 10631da177e4SLinus Torvalds *statp = rpc_system_err; 10641da177e4SLinus Torvalds } 10651da177e4SLinus Torvalds } else { 10661da177e4SLinus Torvalds dprintk("svc: calling dispatcher\n"); 10671da177e4SLinus Torvalds if (!versp->vs_dispatch(rqstp, statp)) { 10681da177e4SLinus Torvalds /* Release reply info */ 10691da177e4SLinus Torvalds if (procp->pc_release) 10701da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 10711da177e4SLinus Torvalds goto dropit; 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds } 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds /* Check RPC status result */ 10761da177e4SLinus Torvalds if (*statp != rpc_success) 10771da177e4SLinus Torvalds resv->iov_len = ((void*)statp) - resv->iov_base + 4; 10781da177e4SLinus Torvalds 10791da177e4SLinus Torvalds /* Release reply info */ 10801da177e4SLinus Torvalds if (procp->pc_release) 10811da177e4SLinus Torvalds procp->pc_release(rqstp, NULL, rqstp->rq_resp); 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds if (procp->pc_encode == NULL) 10841da177e4SLinus Torvalds goto dropit; 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds sendit: 10871da177e4SLinus Torvalds if (svc_authorise(rqstp)) 10881da177e4SLinus Torvalds goto dropit; 10891da177e4SLinus Torvalds return svc_send(rqstp); 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds dropit: 10921da177e4SLinus Torvalds svc_authorise(rqstp); /* doesn't hurt to call this twice */ 10931da177e4SLinus Torvalds dprintk("svc: svc_process dropit\n"); 10941da177e4SLinus Torvalds svc_drop(rqstp); 10951da177e4SLinus Torvalds return 0; 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds err_short_len: 1098354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "short len %Zd, dropping request\n", 1099354ecbb9SDr. David Alan Gilbert argv->iov_len); 110034e9a63bSNeilBrown 11011da177e4SLinus Torvalds goto dropit; /* drop request */ 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds err_bad_dir: 1104354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "bad direction %d, dropping request\n", dir); 110534e9a63bSNeilBrown 11061da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 11071da177e4SLinus Torvalds goto dropit; /* drop request */ 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds err_bad_rpc: 11101da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 111176994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 111276994313SAlexey Dobriyan svc_putnl(resv, 0); /* RPC_MISMATCH */ 111376994313SAlexey Dobriyan svc_putnl(resv, 2); /* Only RPCv2 supported */ 111476994313SAlexey Dobriyan svc_putnl(resv, 2); 11151da177e4SLinus Torvalds goto sendit; 11161da177e4SLinus Torvalds 11171da177e4SLinus Torvalds err_bad_auth: 11181da177e4SLinus Torvalds dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); 11191da177e4SLinus Torvalds serv->sv_stats->rpcbadauth++; 11201da177e4SLinus Torvalds /* Restore write pointer to location of accept status: */ 11218f8e05c5SJ.Bruce Fields xdr_ressize_check(rqstp, reply_statp); 112276994313SAlexey Dobriyan svc_putnl(resv, 1); /* REJECT */ 112376994313SAlexey Dobriyan svc_putnl(resv, 1); /* AUTH_ERROR */ 112476994313SAlexey Dobriyan svc_putnl(resv, ntohl(auth_stat)); /* status */ 11251da177e4SLinus Torvalds goto sendit; 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds err_bad_prog: 11289ba02638SAndreas Gruenbacher dprintk("svc: unknown program %d\n", prog); 11291da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 113076994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_UNAVAIL); 11311da177e4SLinus Torvalds goto sendit; 11321da177e4SLinus Torvalds 11331da177e4SLinus Torvalds err_bad_vers: 1134354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", 11351a8eff6dSNeilBrown vers, prog, progp->pg_name); 113634e9a63bSNeilBrown 11371da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 113876994313SAlexey Dobriyan svc_putnl(resv, RPC_PROG_MISMATCH); 113976994313SAlexey Dobriyan svc_putnl(resv, progp->pg_lovers); 114076994313SAlexey Dobriyan svc_putnl(resv, progp->pg_hivers); 11411da177e4SLinus Torvalds goto sendit; 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds err_bad_proc: 1144354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "unknown procedure (%d)\n", proc); 114534e9a63bSNeilBrown 11461da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 114776994313SAlexey Dobriyan svc_putnl(resv, RPC_PROC_UNAVAIL); 11481da177e4SLinus Torvalds goto sendit; 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds err_garbage: 1151354ecbb9SDr. David Alan Gilbert svc_printk(rqstp, "failed to decode args\n"); 115234e9a63bSNeilBrown 11531da177e4SLinus Torvalds rpc_stat = rpc_garbage_args; 11541da177e4SLinus Torvalds err_bad: 11551da177e4SLinus Torvalds serv->sv_stats->rpcbadfmt++; 115676994313SAlexey Dobriyan svc_putnl(resv, ntohl(rpc_stat)); 11571da177e4SLinus Torvalds goto sendit; 11581da177e4SLinus Torvalds } 1159d2f7e79eSTrond Myklebust EXPORT_SYMBOL(svc_process); 11607adae489SGreg Banks 11617adae489SGreg Banks /* 11627adae489SGreg Banks * Return (transport-specific) limit on the rpc payload. 11637adae489SGreg Banks */ 11647adae489SGreg Banks u32 svc_max_payload(const struct svc_rqst *rqstp) 11657adae489SGreg Banks { 116649023155STom Tucker u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload; 11677adae489SGreg Banks 1168c6b0a9f8SNeilBrown if (rqstp->rq_server->sv_max_payload < max) 1169c6b0a9f8SNeilBrown max = rqstp->rq_server->sv_max_payload; 11707adae489SGreg Banks return max; 11717adae489SGreg Banks } 11727adae489SGreg Banks EXPORT_SYMBOL_GPL(svc_max_payload); 1173