nfsd: make nfsd_svc take an array of thread counts

Now that the refcounting is fixed, rework nfsd_svc to use the same
thread setup as the pool_threads interface. Have it take an array of
thread counts instead of just a single value, and pass that from the
netlink threads set interface. Since the new netlink interface doesn't
have the same restriction as pool_threads, move the guard against
shutting down all threads to write_pool_threads.

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 b4d8f228 8e0c8d23

+45 -24
+10 -2
fs/nfsd/nfsctl.c
··· 406 return -EINVAL; 407 trace_nfsd_ctl_threads(net, newthreads); 408 mutex_lock(&nfsd_mutex); 409 - rv = nfsd_svc(newthreads, net, file->f_cred, NULL); 410 mutex_unlock(&nfsd_mutex); 411 if (rv < 0) 412 return rv; ··· 481 goto out_free; 482 trace_nfsd_ctl_pool_threads(net, i, nthreads[i]); 483 } 484 rv = nfsd_set_nrthreads(i, nthreads, net); 485 if (rv) 486 goto out_free; ··· 1704 scope = nla_data(attr); 1705 } 1706 1707 - ret = nfsd_svc(nthreads, net, get_current_cred(), scope); 1708 1709 out_unlock: 1710 mutex_unlock(&nfsd_mutex);
··· 406 return -EINVAL; 407 trace_nfsd_ctl_threads(net, newthreads); 408 mutex_lock(&nfsd_mutex); 409 + rv = nfsd_svc(1, &newthreads, net, file->f_cred, NULL); 410 mutex_unlock(&nfsd_mutex); 411 if (rv < 0) 412 return rv; ··· 481 goto out_free; 482 trace_nfsd_ctl_pool_threads(net, i, nthreads[i]); 483 } 484 + 485 + /* 486 + * There must always be a thread in pool 0; the admin 487 + * can't shut down NFS completely using pool_threads. 488 + */ 489 + if (nthreads[0] == 0) 490 + nthreads[0] = 1; 491 + 492 rv = nfsd_set_nrthreads(i, nthreads, net); 493 if (rv) 494 goto out_free; ··· 1696 scope = nla_data(attr); 1697 } 1698 1699 + ret = nfsd_svc(1, &nthreads, net, get_current_cred(), scope); 1700 1701 out_unlock: 1702 mutex_unlock(&nfsd_mutex);
+2 -1
fs/nfsd/nfsd.h
··· 103 /* 104 * Function prototypes. 105 */ 106 - int nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope); 107 int nfsd_dispatch(struct svc_rqst *rqstp); 108 109 int nfsd_nrthreads(struct net *);
··· 103 /* 104 * Function prototypes. 105 */ 106 + int nfsd_svc(int n, int *nservers, struct net *net, 107 + const struct cred *cred, const char *scope); 108 int nfsd_dispatch(struct svc_rqst *rqstp); 109 110 int nfsd_nrthreads(struct net *);
+33 -21
fs/nfsd/nfssvc.c
··· 709 return 0; 710 } 711 712 int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) 713 { 714 int i = 0; ··· 729 int err = 0; 730 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 731 732 - WARN_ON(!mutex_is_locked(&nfsd_mutex)); 733 734 if (nn->nfsd_serv == NULL || n <= 0) 735 return 0; 736 737 if (n > nn->nfsd_serv->sv_nrpools) 738 n = nn->nfsd_serv->sv_nrpools; ··· 763 } 764 } 765 766 - /* 767 - * There must always be a thread in pool 0; the admin 768 - * can't shut down NFS completely using pool_threads. 769 - */ 770 - if (nthreads[0] == 0) 771 - nthreads[0] = 1; 772 - 773 /* apply the new numbers */ 774 for (i = 0; i < n; i++) { 775 err = svc_set_num_threads(nn->nfsd_serv, ··· 774 return err; 775 } 776 777 - /* 778 - * Adjust the number of threads and return the new number of threads. 779 - * This is also the function that starts the server if necessary, if 780 - * this is the first time nrservs is nonzero. 781 */ 782 int 783 - nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope) 784 { 785 int error; 786 struct nfsd_net *nn = net_generic(net, nfsd_net_id); ··· 795 lockdep_assert_held(&nfsd_mutex); 796 797 dprintk("nfsd: creating service\n"); 798 - 799 - nrservs = max(nrservs, 0); 800 - nrservs = min(nrservs, NFSD_MAXSERVS); 801 - error = 0; 802 - 803 - if (nrservs == 0 && nn->nfsd_serv == NULL) 804 - goto out; 805 806 strscpy(nn->nfsd_name, scope ? scope : utsname()->nodename, 807 sizeof(nn->nfsd_name)); ··· 807 error = nfsd_startup_net(net, cred); 808 if (error) 809 goto out_put; 810 - error = svc_set_num_threads(serv, NULL, nrservs); 811 if (error) 812 goto out_put; 813 error = serv->sv_nrthreads;
··· 709 return 0; 710 } 711 712 + /** 713 + * nfsd_set_nrthreads - set the number of running threads in the net's service 714 + * @n: number of array members in @nthreads 715 + * @nthreads: array of thread counts for each pool 716 + * @net: network namespace to operate within 717 + * 718 + * This function alters the number of running threads for the given network 719 + * namespace in each pool. If passed an array longer then the number of pools 720 + * the extra pool settings are ignored. If passed an array shorter than the 721 + * number of pools, the missing values are interpreted as 0's. 722 + * 723 + * Returns 0 on success or a negative errno on error. 724 + */ 725 int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) 726 { 727 int i = 0; ··· 716 int err = 0; 717 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 718 719 + lockdep_assert_held(&nfsd_mutex); 720 721 if (nn->nfsd_serv == NULL || n <= 0) 722 return 0; 723 + 724 + /* 725 + * Special case: When n == 1, pass in NULL for the pool, so that the 726 + * change is distributed equally among them. 727 + */ 728 + if (n == 1) 729 + return svc_set_num_threads(nn->nfsd_serv, NULL, nthreads[0]); 730 731 if (n > nn->nfsd_serv->sv_nrpools) 732 n = nn->nfsd_serv->sv_nrpools; ··· 743 } 744 } 745 746 /* apply the new numbers */ 747 for (i = 0; i < n; i++) { 748 err = svc_set_num_threads(nn->nfsd_serv, ··· 761 return err; 762 } 763 764 + /** 765 + * nfsd_svc: start up or shut down the nfsd server 766 + * @n: number of array members in @nthreads 767 + * @nthreads: array of thread counts for each pool 768 + * @net: network namespace to operate within 769 + * @cred: credentials to use for xprt creation 770 + * @scope: server scope value (defaults to nodename) 771 + * 772 + * Adjust the number of threads in each pool and return the new 773 + * total number of threads in the service. 774 */ 775 int 776 + nfsd_svc(int n, int *nthreads, struct net *net, const struct cred *cred, const char *scope) 777 { 778 int error; 779 struct nfsd_net *nn = net_generic(net, nfsd_net_id); ··· 776 lockdep_assert_held(&nfsd_mutex); 777 778 dprintk("nfsd: creating service\n"); 779 780 strscpy(nn->nfsd_name, scope ? scope : utsname()->nodename, 781 sizeof(nn->nfsd_name)); ··· 795 error = nfsd_startup_net(net, cred); 796 if (error) 797 goto out_put; 798 + error = nfsd_set_nrthreads(n, nthreads, net); 799 if (error) 800 goto out_put; 801 error = serv->sv_nrthreads;