SUNRPC: replace program list with program array

A service created with svc_create_pooled() can be given a linked list of
programs and all of these will be served.

Using a linked list makes it cumbersome when there are several programs
that can be optionally selected with CONFIG settings.

After this patch is applied, API consumers must use only
svc_create_pooled() when creating an RPC service that listens for more
than one RPC program.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
This commit is contained in:
NeilBrown 2024-09-05 15:09:47 -04:00 committed by Anna Schumaker
parent 199f212874
commit 86ab08beb3
7 changed files with 67 additions and 55 deletions

View File

@ -2246,7 +2246,7 @@ static __net_init int nfsd_net_init(struct net *net)
if (retval) if (retval)
goto out_repcache_error; goto out_repcache_error;
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats)); memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
nn->nfsd_svcstats.program = &nfsd_program; nn->nfsd_svcstats.program = &nfsd_programs[0];
for (i = 0; i < sizeof(nn->nfsd_versions); i++) for (i = 0; i < sizeof(nn->nfsd_versions); i++)
nn->nfsd_versions[i] = nfsd_support_version(i); nn->nfsd_versions[i] = nfsd_support_version(i);
for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++) for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)

View File

@ -85,7 +85,7 @@ struct nfsd_genl_rqstp {
u32 rq_opnum[NFSD_MAX_OPS_PER_COMPOUND]; u32 rq_opnum[NFSD_MAX_OPS_PER_COMPOUND];
}; };
extern struct svc_program nfsd_program; extern struct svc_program nfsd_programs[];
extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
extern struct mutex nfsd_mutex; extern struct mutex nfsd_mutex;
extern spinlock_t nfsd_drc_lock; extern spinlock_t nfsd_drc_lock;

View File

@ -35,7 +35,6 @@
#define NFSDDBG_FACILITY NFSDDBG_SVC #define NFSDDBG_FACILITY NFSDDBG_SVC
atomic_t nfsd_th_cnt = ATOMIC_INIT(0); atomic_t nfsd_th_cnt = ATOMIC_INIT(0);
extern struct svc_program nfsd_program;
static int nfsd(void *vrqstp); static int nfsd(void *vrqstp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static int nfsd_acl_rpcbind_set(struct net *, static int nfsd_acl_rpcbind_set(struct net *,
@ -93,17 +92,6 @@ static const struct svc_version *nfsd_acl_version[] = {
#define NFSD_ACL_MINVERS 2 #define NFSD_ACL_MINVERS 2
#define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version) #define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version)
static struct svc_program nfsd_acl_program = {
.pg_prog = NFS_ACL_PROGRAM,
.pg_nvers = NFSD_ACL_NRVERS,
.pg_vers = nfsd_acl_version,
.pg_name = "nfsacl",
.pg_class = "nfsd",
.pg_authenticate = &svc_set_client,
.pg_init_request = nfsd_acl_init_request,
.pg_rpcbind_set = nfsd_acl_rpcbind_set,
};
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
static const struct svc_version *nfsd_version[NFSD_MAXVERS+1] = { static const struct svc_version *nfsd_version[NFSD_MAXVERS+1] = {
@ -116,18 +104,29 @@ static const struct svc_version *nfsd_version[NFSD_MAXVERS+1] = {
#endif #endif
}; };
struct svc_program nfsd_program = { struct svc_program nfsd_programs[] = {
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) {
.pg_next = &nfsd_acl_program,
#endif
.pg_prog = NFS_PROGRAM, /* program number */ .pg_prog = NFS_PROGRAM, /* program number */
.pg_nvers = NFSD_MAXVERS+1, /* nr of entries in nfsd_version */ .pg_nvers = NFSD_MAXVERS+1, /* nr of entries in nfsd_version */
.pg_vers = nfsd_version, /* version table */ .pg_vers = nfsd_version, /* version table */
.pg_name = "nfsd", /* program name */ .pg_name = "nfsd", /* program name */
.pg_class = "nfsd", /* authentication class */ .pg_class = "nfsd", /* authentication class */
.pg_authenticate = &svc_set_client, /* export authentication */ .pg_authenticate = svc_set_client, /* export authentication */
.pg_init_request = nfsd_init_request, .pg_init_request = nfsd_init_request,
.pg_rpcbind_set = nfsd_rpcbind_set, .pg_rpcbind_set = nfsd_rpcbind_set,
},
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
{
.pg_prog = NFS_ACL_PROGRAM,
.pg_nvers = NFSD_ACL_NRVERS,
.pg_vers = nfsd_acl_version,
.pg_name = "nfsacl",
.pg_class = "nfsd",
.pg_authenticate = svc_set_client,
.pg_init_request = nfsd_acl_init_request,
.pg_rpcbind_set = nfsd_acl_rpcbind_set,
},
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
}; };
bool nfsd_support_version(int vers) bool nfsd_support_version(int vers)
@ -641,7 +640,8 @@ int nfsd_create_serv(struct net *net)
if (nfsd_max_blksize == 0) if (nfsd_max_blksize == 0)
nfsd_max_blksize = nfsd_get_default_max_blksize(); nfsd_max_blksize = nfsd_get_default_max_blksize();
nfsd_reset_versions(nn); nfsd_reset_versions(nn);
serv = svc_create_pooled(&nfsd_program, &nn->nfsd_svcstats, serv = svc_create_pooled(nfsd_programs, ARRAY_SIZE(nfsd_programs),
&nn->nfsd_svcstats,
nfsd_max_blksize, nfsd); nfsd_max_blksize, nfsd);
if (serv == NULL) if (serv == NULL)
return -ENOMEM; return -ENOMEM;

View File

@ -67,9 +67,10 @@ enum {
* We currently do not support more than one RPC program per daemon. * We currently do not support more than one RPC program per daemon.
*/ */
struct svc_serv { struct svc_serv {
struct svc_program * sv_program; /* RPC program */ struct svc_program * sv_programs; /* RPC programs */
struct svc_stat * sv_stats; /* RPC statistics */ struct svc_stat * sv_stats; /* RPC statistics */
spinlock_t sv_lock; spinlock_t sv_lock;
unsigned int sv_nprogs; /* Number of sv_programs */
unsigned int sv_nrthreads; /* # of server threads */ unsigned int sv_nrthreads; /* # of server threads */
unsigned int sv_maxconn; /* max connections allowed or unsigned int sv_maxconn; /* max connections allowed or
* '0' causing max to be based * '0' causing max to be based
@ -360,10 +361,9 @@ struct svc_process_info {
}; };
/* /*
* List of RPC programs on the same transport endpoint * RPC program - an array of these can use the same transport endpoint
*/ */
struct svc_program { struct svc_program {
struct svc_program * pg_next; /* other programs (same xprt) */
u32 pg_prog; /* program number */ u32 pg_prog; /* program number */
unsigned int pg_lovers; /* lowest version */ unsigned int pg_lovers; /* lowest version */
unsigned int pg_hivers; /* highest version */ unsigned int pg_hivers; /* highest version */
@ -441,6 +441,7 @@ bool svc_rqst_replace_page(struct svc_rqst *rqstp,
void svc_rqst_release_pages(struct svc_rqst *rqstp); void svc_rqst_release_pages(struct svc_rqst *rqstp);
void svc_exit_thread(struct svc_rqst *); void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *prog, struct svc_serv * svc_create_pooled(struct svc_program *prog,
unsigned int nprog,
struct svc_stat *stats, struct svc_stat *stats,
unsigned int bufsize, unsigned int bufsize,
int (*threadfn)(void *data)); int (*threadfn)(void *data));

View File

@ -440,10 +440,11 @@ EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
static int svc_uses_rpcbind(struct svc_serv *serv) static int svc_uses_rpcbind(struct svc_serv *serv)
{ {
struct svc_program *progp; unsigned int p, i;
unsigned int i;
for (p = 0; p < serv->sv_nprogs; p++) {
struct svc_program *progp = &serv->sv_programs[p];
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
for (i = 0; i < progp->pg_nvers; i++) { for (i = 0; i < progp->pg_nvers; i++) {
if (progp->pg_vers[i] == NULL) if (progp->pg_vers[i] == NULL)
continue; continue;
@ -480,7 +481,7 @@ __svc_init_bc(struct svc_serv *serv)
* Create an RPC service * Create an RPC service
*/ */
static struct svc_serv * static struct svc_serv *
__svc_create(struct svc_program *prog, struct svc_stat *stats, __svc_create(struct svc_program *prog, int nprogs, struct svc_stat *stats,
unsigned int bufsize, int npools, int (*threadfn)(void *data)) unsigned int bufsize, int npools, int (*threadfn)(void *data))
{ {
struct svc_serv *serv; struct svc_serv *serv;
@ -491,7 +492,8 @@ __svc_create(struct svc_program *prog, struct svc_stat *stats,
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL; return NULL;
serv->sv_name = prog->pg_name; serv->sv_name = prog->pg_name;
serv->sv_program = prog; serv->sv_programs = prog;
serv->sv_nprogs = nprogs;
serv->sv_stats = stats; serv->sv_stats = stats;
if (bufsize > RPCSVC_MAXPAYLOAD) if (bufsize > RPCSVC_MAXPAYLOAD)
bufsize = RPCSVC_MAXPAYLOAD; bufsize = RPCSVC_MAXPAYLOAD;
@ -499,17 +501,18 @@ __svc_create(struct svc_program *prog, struct svc_stat *stats,
serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
serv->sv_threadfn = threadfn; serv->sv_threadfn = threadfn;
xdrsize = 0; xdrsize = 0;
while (prog) { for (i = 0; i < nprogs; i++) {
prog->pg_lovers = prog->pg_nvers-1; struct svc_program *progp = &prog[i];
for (vers=0; vers<prog->pg_nvers ; vers++)
if (prog->pg_vers[vers]) { progp->pg_lovers = progp->pg_nvers-1;
prog->pg_hivers = vers; for (vers = 0; vers < progp->pg_nvers ; vers++)
if (prog->pg_lovers > vers) if (progp->pg_vers[vers]) {
prog->pg_lovers = vers; progp->pg_hivers = vers;
if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) if (progp->pg_lovers > vers)
xdrsize = prog->pg_vers[vers]->vs_xdrsize; progp->pg_lovers = vers;
if (progp->pg_vers[vers]->vs_xdrsize > xdrsize)
xdrsize = progp->pg_vers[vers]->vs_xdrsize;
} }
prog = prog->pg_next;
} }
serv->sv_xdrsize = xdrsize; serv->sv_xdrsize = xdrsize;
INIT_LIST_HEAD(&serv->sv_tempsocks); INIT_LIST_HEAD(&serv->sv_tempsocks);
@ -558,13 +561,14 @@ __svc_create(struct svc_program *prog, struct svc_stat *stats,
struct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize, struct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize,
int (*threadfn)(void *data)) int (*threadfn)(void *data))
{ {
return __svc_create(prog, NULL, bufsize, 1, threadfn); return __svc_create(prog, 1, NULL, bufsize, 1, threadfn);
} }
EXPORT_SYMBOL_GPL(svc_create); EXPORT_SYMBOL_GPL(svc_create);
/** /**
* svc_create_pooled - Create an RPC service with pooled threads * svc_create_pooled - Create an RPC service with pooled threads
* @prog: the RPC program the new service will handle * @prog: Array of RPC programs the new service will handle
* @nprogs: Number of programs in the array
* @stats: the stats struct if desired * @stats: the stats struct if desired
* @bufsize: maximum message size for @prog * @bufsize: maximum message size for @prog
* @threadfn: a function to service RPC requests for @prog * @threadfn: a function to service RPC requests for @prog
@ -572,6 +576,7 @@ EXPORT_SYMBOL_GPL(svc_create);
* Returns an instantiated struct svc_serv object or NULL. * Returns an instantiated struct svc_serv object or NULL.
*/ */
struct svc_serv *svc_create_pooled(struct svc_program *prog, struct svc_serv *svc_create_pooled(struct svc_program *prog,
unsigned int nprogs,
struct svc_stat *stats, struct svc_stat *stats,
unsigned int bufsize, unsigned int bufsize,
int (*threadfn)(void *data)) int (*threadfn)(void *data))
@ -579,7 +584,7 @@ struct svc_serv *svc_create_pooled(struct svc_program *prog,
struct svc_serv *serv; struct svc_serv *serv;
unsigned int npools = svc_pool_map_get(); unsigned int npools = svc_pool_map_get();
serv = __svc_create(prog, stats, bufsize, npools, threadfn); serv = __svc_create(prog, nprogs, stats, bufsize, npools, threadfn);
if (!serv) if (!serv)
goto out_err; goto out_err;
serv->sv_is_pooled = true; serv->sv_is_pooled = true;
@ -602,16 +607,16 @@ svc_destroy(struct svc_serv **servp)
*servp = NULL; *servp = NULL;
dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name); dprintk("svc: svc_destroy(%s)\n", serv->sv_programs->pg_name);
timer_shutdown_sync(&serv->sv_temptimer); timer_shutdown_sync(&serv->sv_temptimer);
/* /*
* Remaining transports at this point are not expected. * Remaining transports at this point are not expected.
*/ */
WARN_ONCE(!list_empty(&serv->sv_permsocks), WARN_ONCE(!list_empty(&serv->sv_permsocks),
"SVC: permsocks remain for %s\n", serv->sv_program->pg_name); "SVC: permsocks remain for %s\n", serv->sv_programs->pg_name);
WARN_ONCE(!list_empty(&serv->sv_tempsocks), WARN_ONCE(!list_empty(&serv->sv_tempsocks),
"SVC: tempsocks remain for %s\n", serv->sv_program->pg_name); "SVC: tempsocks remain for %s\n", serv->sv_programs->pg_name);
cache_clean_deferred(serv); cache_clean_deferred(serv);
@ -1148,15 +1153,16 @@ int svc_register(const struct svc_serv *serv, struct net *net,
const int family, const unsigned short proto, const int family, const unsigned short proto,
const unsigned short port) const unsigned short port)
{ {
struct svc_program *progp; unsigned int p, i;
unsigned int i;
int error = 0; int error = 0;
WARN_ON_ONCE(proto == 0 && port == 0); WARN_ON_ONCE(proto == 0 && port == 0);
if (proto == 0 && port == 0) if (proto == 0 && port == 0)
return -EINVAL; return -EINVAL;
for (progp = serv->sv_program; progp; progp = progp->pg_next) { for (p = 0; p < serv->sv_nprogs; p++) {
struct svc_program *progp = &serv->sv_programs[p];
for (i = 0; i < progp->pg_nvers; i++) { for (i = 0; i < progp->pg_nvers; i++) {
error = progp->pg_rpcbind_set(net, progp, i, error = progp->pg_rpcbind_set(net, progp, i,
@ -1208,13 +1214,14 @@ static void __svc_unregister(struct net *net, const u32 program, const u32 versi
static void svc_unregister(const struct svc_serv *serv, struct net *net) static void svc_unregister(const struct svc_serv *serv, struct net *net)
{ {
struct sighand_struct *sighand; struct sighand_struct *sighand;
struct svc_program *progp;
unsigned long flags; unsigned long flags;
unsigned int i; unsigned int p, i;
clear_thread_flag(TIF_SIGPENDING); clear_thread_flag(TIF_SIGPENDING);
for (progp = serv->sv_program; progp; progp = progp->pg_next) { for (p = 0; p < serv->sv_nprogs; p++) {
struct svc_program *progp = &serv->sv_programs[p];
for (i = 0; i < progp->pg_nvers; i++) { for (i = 0; i < progp->pg_nvers; i++) {
if (progp->pg_vers[i] == NULL) if (progp->pg_vers[i] == NULL)
continue; continue;
@ -1320,7 +1327,7 @@ svc_process_common(struct svc_rqst *rqstp)
struct svc_process_info process; struct svc_process_info process;
enum svc_auth_status auth_res; enum svc_auth_status auth_res;
unsigned int aoffset; unsigned int aoffset;
int rc; int pr, rc;
__be32 *p; __be32 *p;
/* Will be turned off only when NFSv4 Sessions are used */ /* Will be turned off only when NFSv4 Sessions are used */
@ -1344,9 +1351,12 @@ svc_process_common(struct svc_rqst *rqstp)
rqstp->rq_vers = be32_to_cpup(p++); rqstp->rq_vers = be32_to_cpup(p++);
rqstp->rq_proc = be32_to_cpup(p); rqstp->rq_proc = be32_to_cpup(p);
for (progp = serv->sv_program; progp; progp = progp->pg_next) for (pr = 0; pr < serv->sv_nprogs; pr++) {
progp = &serv->sv_programs[pr];
if (rqstp->rq_prog == progp->pg_prog) if (rqstp->rq_prog == progp->pg_prog)
break; break;
}
/* /*
* Decode auth data, and add verifier to reply buffer. * Decode auth data, and add verifier to reply buffer.

View File

@ -268,7 +268,7 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
spin_unlock(&svc_xprt_class_lock); spin_unlock(&svc_xprt_class_lock);
newxprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); newxprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
if (IS_ERR(newxprt)) { if (IS_ERR(newxprt)) {
trace_svc_xprt_create_err(serv->sv_program->pg_name, trace_svc_xprt_create_err(serv->sv_programs->pg_name,
xcl->xcl_name, sap, len, xcl->xcl_name, sap, len,
newxprt); newxprt);
module_put(xcl->xcl_owner); module_put(xcl->xcl_owner);

View File

@ -697,7 +697,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
rqstp->rq_auth_stat = rpc_autherr_badcred; rqstp->rq_auth_stat = rpc_autherr_badcred;
ipm = ip_map_cached_get(xprt); ipm = ip_map_cached_get(xprt);
if (ipm == NULL) if (ipm == NULL)
ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class, ipm = __ip_map_lookup(sn->ip_map_cache,
rqstp->rq_server->sv_programs->pg_class,
&sin6->sin6_addr); &sin6->sin6_addr);
if (ipm == NULL) if (ipm == NULL)