Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] knfsd: provide sunrpc pool_mode module option

Provide a module param "pool_mode" for sunrpc.ko which allows a sysadmin to
choose the mode for mapping NFS thread service pools to CPUs. Values are:

auto choose a mapping mode heuristically
global (default, same as the pre-2.6.19 code) a single global pool
percpu one pool per CPU
pernode one pool per NUMA node

Note that since 2.6.19 the hardcoded behaviour has been "auto", this patch
makes the default "global".

The pool mode can be changed after boot/modprobe using /sys, if the NFS and
lockd services have been shut down. A useful side effect of this change is to
fix a small memory leak when unloading the module.

Signed-off-by: Greg Banks <gnb@melbourne.sgi.com>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Greg Banks and committed by
Linus Torvalds
42a7fc4a cda1fd4a

+131 -20
+16
Documentation/kernel-parameters.txt
··· 1685 1685 stifb= [HW] 1686 1686 Format: bpp:<bpp1>[:<bpp2>[:<bpp3>...]] 1687 1687 1688 + sunrpc.pool_mode= 1689 + [NFS] 1690 + Control how the NFS server code allocates CPUs to 1691 + service thread pools. Depending on how many NICs 1692 + you have and where their interrupts are bound, this 1693 + option will affect which CPUs will do NFS serving. 1694 + Note: this parameter cannot be changed while the 1695 + NFS server is running. 1696 + 1697 + auto the server chooses an appropriate mode 1698 + automatically using heuristics 1699 + global a single global pool contains all CPUs 1700 + percpu one pool for each CPU 1701 + pernode one pool for each NUMA node (equivalent 1702 + to global on non-NUMA machines) 1703 + 1688 1704 swiotlb= [IA-64] Number of I/O TLB slabs 1689 1705 1690 1706 switches= [HW,M68k]
+115 -20
net/sunrpc/svc.c
··· 27 27 28 28 #define RPCDBG_FACILITY RPCDBG_SVCDSP 29 29 30 + #define svc_serv_is_pooled(serv) ((serv)->sv_function) 31 + 30 32 /* 31 33 * Mode for mapping cpus to pools. 32 34 */ 33 35 enum { 34 - SVC_POOL_NONE = -1, /* uninitialised, choose one of the others */ 36 + SVC_POOL_AUTO = -1, /* choose one of the others */ 35 37 SVC_POOL_GLOBAL, /* no mapping, just a single global pool 36 38 * (legacy & UP mode) */ 37 39 SVC_POOL_PERCPU, /* one pool per cpu */ 38 40 SVC_POOL_PERNODE /* one pool per numa node */ 39 41 }; 42 + #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL 40 43 41 44 /* 42 45 * Structure for mapping cpus to pools and vice versa. 43 46 * Setup once during sunrpc initialisation. 44 47 */ 45 48 static struct svc_pool_map { 49 + int count; /* How many svc_servs use us */ 46 50 int mode; /* Note: int not enum to avoid 47 51 * warnings about "enumeration value 48 52 * not handled in switch" */ ··· 54 50 unsigned int *pool_to; /* maps pool id to cpu or node */ 55 51 unsigned int *to_pool; /* maps cpu or node to pool id */ 56 52 } svc_pool_map = { 57 - .mode = SVC_POOL_NONE 53 + .count = 0, 54 + .mode = SVC_POOL_DEFAULT 58 55 }; 56 + static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ 59 57 58 + static int 59 + param_set_pool_mode(const char *val, struct kernel_param *kp) 60 + { 61 + int *ip = (int *)kp->arg; 62 + struct svc_pool_map *m = &svc_pool_map; 63 + int err; 64 + 65 + mutex_lock(&svc_pool_map_mutex); 66 + 67 + err = -EBUSY; 68 + if (m->count) 69 + goto out; 70 + 71 + err = 0; 72 + if (!strncmp(val, "auto", 4)) 73 + *ip = SVC_POOL_AUTO; 74 + else if (!strncmp(val, "global", 6)) 75 + *ip = SVC_POOL_GLOBAL; 76 + else if (!strncmp(val, "percpu", 6)) 77 + *ip = SVC_POOL_PERCPU; 78 + else if (!strncmp(val, "pernode", 7)) 79 + *ip = SVC_POOL_PERNODE; 80 + else 81 + err = -EINVAL; 82 + 83 + out: 84 + mutex_unlock(&svc_pool_map_mutex); 85 + return err; 86 + } 87 + 88 + static int 89 + param_get_pool_mode(char *buf, struct kernel_param *kp) 90 + { 91 + int *ip = (int *)kp->arg; 92 + 93 + switch (*ip) 94 + { 95 + case SVC_POOL_AUTO: 96 + return strlcpy(buf, "auto", 20); 97 + case SVC_POOL_GLOBAL: 98 + return strlcpy(buf, "global", 20); 99 + case SVC_POOL_PERCPU: 100 + return strlcpy(buf, "percpu", 20); 101 + case SVC_POOL_PERNODE: 102 + return strlcpy(buf, "pernode", 20); 103 + default: 104 + return sprintf(buf, "%d", *ip); 105 + } 106 + } 107 + 108 + module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode, 109 + &svc_pool_map.mode, 0644); 60 110 61 111 /* 62 112 * Detect best pool mapping mode heuristically, ··· 224 166 225 167 226 168 /* 227 - * Build the global map of cpus to pools and vice versa. 169 + * Add a reference to the global map of cpus to pools (and 170 + * vice versa). Initialise the map if we're the first user. 171 + * Returns the number of pools. 228 172 */ 229 173 static unsigned int 230 - svc_pool_map_init(void) 174 + svc_pool_map_get(void) 231 175 { 232 176 struct svc_pool_map *m = &svc_pool_map; 233 177 int npools = -1; 234 178 235 - if (m->mode != SVC_POOL_NONE) 236 - return m->npools; 179 + mutex_lock(&svc_pool_map_mutex); 237 180 238 - m->mode = svc_pool_map_choose_mode(); 181 + if (m->count++) { 182 + mutex_unlock(&svc_pool_map_mutex); 183 + return m->npools; 184 + } 185 + 186 + if (m->mode == SVC_POOL_AUTO) 187 + m->mode = svc_pool_map_choose_mode(); 239 188 240 189 switch (m->mode) { 241 190 case SVC_POOL_PERCPU: ··· 260 195 } 261 196 m->npools = npools; 262 197 198 + mutex_unlock(&svc_pool_map_mutex); 263 199 return m->npools; 264 200 } 201 + 202 + 203 + /* 204 + * Drop a reference to the global map of cpus to pools. 205 + * When the last reference is dropped, the map data is 206 + * freed; this allows the sysadmin to change the pool 207 + * mode using the pool_mode module option without 208 + * rebooting or re-loading sunrpc.ko. 209 + */ 210 + static void 211 + svc_pool_map_put(void) 212 + { 213 + struct svc_pool_map *m = &svc_pool_map; 214 + 215 + mutex_lock(&svc_pool_map_mutex); 216 + 217 + if (!--m->count) { 218 + m->mode = SVC_POOL_DEFAULT; 219 + kfree(m->to_pool); 220 + kfree(m->pool_to); 221 + m->npools = 0; 222 + } 223 + 224 + mutex_unlock(&svc_pool_map_mutex); 225 + } 226 + 265 227 266 228 /* 267 229 * Set the current thread's cpus_allowed mask so that it ··· 304 212 305 213 /* 306 214 * The caller checks for sv_nrpools > 1, which 307 - * implies that we've been initialized and the 308 - * map mode is not NONE. 215 + * implies that we've been initialized. 309 216 */ 310 - BUG_ON(m->mode == SVC_POOL_NONE); 217 + BUG_ON(m->count == 0); 311 218 312 219 switch (m->mode) 313 220 { ··· 337 246 unsigned int pidx = 0; 338 247 339 248 /* 340 - * SVC_POOL_NONE happens in a pure client when 249 + * An uninitialised map happens in a pure client when 341 250 * lockd is brought up, so silently treat it the 342 251 * same as SVC_POOL_GLOBAL. 343 252 */ 344 - 345 - switch (m->mode) { 346 - case SVC_POOL_PERCPU: 347 - pidx = m->to_pool[cpu]; 348 - break; 349 - case SVC_POOL_PERNODE: 350 - pidx = m->to_pool[cpu_to_node(cpu)]; 351 - break; 253 + if (svc_serv_is_pooled(serv)) { 254 + switch (m->mode) { 255 + case SVC_POOL_PERCPU: 256 + pidx = m->to_pool[cpu]; 257 + break; 258 + case SVC_POOL_PERNODE: 259 + pidx = m->to_pool[cpu_to_node(cpu)]; 260 + break; 261 + } 352 262 } 353 263 return &serv->sv_pools[pidx % serv->sv_nrpools]; 354 264 } ··· 439 347 svc_thread_fn func, int sig, struct module *mod) 440 348 { 441 349 struct svc_serv *serv; 442 - unsigned int npools = svc_pool_map_init(); 350 + unsigned int npools = svc_pool_map_get(); 443 351 444 352 serv = __svc_create(prog, bufsize, npools, shutdown); 445 353 ··· 488 396 BUG_ON(!list_empty(&serv->sv_tempsocks)); 489 397 490 398 cache_clean_deferred(serv); 399 + 400 + if (svc_serv_is_pooled(serv)) 401 + svc_pool_map_put(); 491 402 492 403 /* Unregister service with the portmapper */ 493 404 svc_register(serv, 0, 0);