sunrpc: fix up the special handling of sv_nrpools == 1

Only pooled services take a reference to the svc_pool_map. The sunrpc
code has always used the sv_nrpools value to detect whether the service
is pooled.

The problem there is that nfsd is a pooled service, but when it's
running in "global" pool_mode, it doesn't take a reference to the pool
map because it has a sv_nrpools value of 1. This means that we have
two separate codepaths for starting the server, depending on whether
it's pooled or not.

Fix this by adding a new flag to the svc_serv, that indicates whether
the serv is pooled. With this we can have the nfsd service
unconditionally take a reference, regardless of pool_mode.

Note that this is a behavior change for
/sys/module/sunrpc/parameters/pool_mode. Usually this file does not
allow you to change the pool-mode while there are nfsd threads running,
but if the pool-mode is "global" it's allowed. My assumption is that
this is a bug, since it probably should never have worked this way.

This patch changes the behavior such that you get back EBUSY even
when nfsd is running in global mode. I think this is more reasonable
behavior, and given that most people set this today using the module
parameter, it's doubtful anyone will notice.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by Jeff Layton and committed by Chuck Lever 8e0c8d23 3a6adfca

+8 -19
+1
include/linux/sunrpc/svc.h
··· 85 char * sv_name; /* service name */ 86 87 unsigned int sv_nrpools; /* number of thread pools */ 88 struct svc_pool * sv_pools; /* array of thread pools */ 89 int (*sv_threadfn)(void *data); 90
··· 85 char * sv_name; /* service name */ 86 87 unsigned int sv_nrpools; /* number of thread pools */ 88 + bool sv_is_pooled; /* is this a pooled service? */ 89 struct svc_pool * sv_pools; /* array of thread pools */ 90 int (*sv_threadfn)(void *data); 91
+7 -19
net/sunrpc/svc.c
··· 250 int npools = -1; 251 252 mutex_lock(&svc_pool_map_mutex); 253 - 254 if (m->count++) { 255 mutex_unlock(&svc_pool_map_mutex); 256 - WARN_ON_ONCE(m->npools <= 1); 257 return m->npools; 258 } 259 ··· 273 m->mode = SVC_POOL_GLOBAL; 274 } 275 m->npools = npools; 276 - 277 - if (npools == 1) 278 - /* service is unpooled, so doesn't hold a reference */ 279 - m->count--; 280 - 281 mutex_unlock(&svc_pool_map_mutex); 282 return npools; 283 } 284 285 /* 286 - * Drop a reference to the global map of cpus to pools, if 287 - * pools were in use, i.e. if npools > 1. 288 * When the last reference is dropped, the map data is 289 - * freed; this allows the sysadmin to change the pool 290 - * mode using the pool_mode module option without 291 - * rebooting or re-loading sunrpc.ko. 292 */ 293 static void 294 - svc_pool_map_put(int npools) 295 { 296 struct svc_pool_map *m = &svc_pool_map; 297 298 - if (npools <= 1) 299 - return; 300 mutex_lock(&svc_pool_map_mutex); 301 - 302 if (!--m->count) { 303 kfree(m->to_pool); 304 m->to_pool = NULL; ··· 295 m->pool_to = NULL; 296 m->npools = 0; 297 } 298 - 299 mutex_unlock(&svc_pool_map_mutex); 300 } 301 ··· 539 serv = __svc_create(prog, stats, bufsize, npools, threadfn); 540 if (!serv) 541 goto out_err; 542 return serv; 543 out_err: 544 - svc_pool_map_put(npools); 545 return NULL; 546 } 547 EXPORT_SYMBOL_GPL(svc_create_pooled); ··· 572 573 cache_clean_deferred(serv); 574 575 - svc_pool_map_put(serv->sv_nrpools); 576 577 for (i = 0; i < serv->sv_nrpools; i++) { 578 struct svc_pool *pool = &serv->sv_pools[i];
··· 250 int npools = -1; 251 252 mutex_lock(&svc_pool_map_mutex); 253 if (m->count++) { 254 mutex_unlock(&svc_pool_map_mutex); 255 return m->npools; 256 } 257 ··· 275 m->mode = SVC_POOL_GLOBAL; 276 } 277 m->npools = npools; 278 mutex_unlock(&svc_pool_map_mutex); 279 return npools; 280 } 281 282 /* 283 + * Drop a reference to the global map of cpus to pools. 284 * When the last reference is dropped, the map data is 285 + * freed; this allows the sysadmin to change the pool. 286 */ 287 static void 288 + svc_pool_map_put(void) 289 { 290 struct svc_pool_map *m = &svc_pool_map; 291 292 mutex_lock(&svc_pool_map_mutex); 293 if (!--m->count) { 294 kfree(m->to_pool); 295 m->to_pool = NULL; ··· 308 m->pool_to = NULL; 309 m->npools = 0; 310 } 311 mutex_unlock(&svc_pool_map_mutex); 312 } 313 ··· 553 serv = __svc_create(prog, stats, bufsize, npools, threadfn); 554 if (!serv) 555 goto out_err; 556 + serv->sv_is_pooled = true; 557 return serv; 558 out_err: 559 + svc_pool_map_put(); 560 return NULL; 561 } 562 EXPORT_SYMBOL_GPL(svc_create_pooled); ··· 585 586 cache_clean_deferred(serv); 587 588 + if (serv->sv_is_pooled) 589 + svc_pool_map_put(); 590 591 for (i = 0; i < serv->sv_nrpools; i++) { 592 struct svc_pool *pool = &serv->sv_pools[i];