SUNRPC: Add a callback to initialise server requests
Add a callback to help initialise server requests before they are processed. This will allow us to clean up the NFS server version support, and to make it container safe. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
83dd59a0b9
commit
8e5b67731d
5 changed files with 98 additions and 39 deletions
|
@ -807,5 +807,6 @@ static struct svc_program nlmsvc_program = {
|
||||||
.pg_name = "lockd", /* service name */
|
.pg_name = "lockd", /* service name */
|
||||||
.pg_class = "nfsd", /* share authentication with nfsd */
|
.pg_class = "nfsd", /* share authentication with nfsd */
|
||||||
.pg_stats = &nlmsvc_stats, /* stats table */
|
.pg_stats = &nlmsvc_stats, /* stats table */
|
||||||
.pg_authenticate = &lockd_authenticate /* export authentication */
|
.pg_authenticate = &lockd_authenticate, /* export authentication */
|
||||||
|
.pg_init_request = svc_generic_init_request,
|
||||||
};
|
};
|
||||||
|
|
|
@ -457,4 +457,5 @@ static struct svc_program nfs4_callback_program = {
|
||||||
.pg_class = "nfs", /* authentication class */
|
.pg_class = "nfs", /* authentication class */
|
||||||
.pg_stats = &nfs4_callback_stats,
|
.pg_stats = &nfs4_callback_stats,
|
||||||
.pg_authenticate = nfs_callback_authenticate,
|
.pg_authenticate = nfs_callback_authenticate,
|
||||||
|
.pg_init_request = svc_generic_init_request,
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,6 +86,7 @@ static struct svc_program nfsd_acl_program = {
|
||||||
.pg_class = "nfsd",
|
.pg_class = "nfsd",
|
||||||
.pg_stats = &nfsd_acl_svcstats,
|
.pg_stats = &nfsd_acl_svcstats,
|
||||||
.pg_authenticate = &svc_set_client,
|
.pg_authenticate = &svc_set_client,
|
||||||
|
.pg_init_request = svc_generic_init_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct svc_stat nfsd_acl_svcstats = {
|
static struct svc_stat nfsd_acl_svcstats = {
|
||||||
|
@ -118,6 +119,7 @@ struct svc_program nfsd_program = {
|
||||||
.pg_class = "nfsd", /* authentication class */
|
.pg_class = "nfsd", /* authentication class */
|
||||||
.pg_stats = &nfsd_svcstats, /* version table */
|
.pg_stats = &nfsd_svcstats, /* version table */
|
||||||
.pg_authenticate = &svc_set_client, /* export authentication */
|
.pg_authenticate = &svc_set_client, /* export authentication */
|
||||||
|
.pg_init_request = svc_generic_init_request,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -383,6 +383,16 @@ struct svc_deferred_req {
|
||||||
__be32 args[0];
|
__be32 args[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct svc_process_info {
|
||||||
|
union {
|
||||||
|
int (*dispatch)(struct svc_rqst *, __be32 *);
|
||||||
|
struct {
|
||||||
|
unsigned int lovers;
|
||||||
|
unsigned int hivers;
|
||||||
|
} mismatch;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of RPC programs on the same transport endpoint
|
* List of RPC programs on the same transport endpoint
|
||||||
*/
|
*/
|
||||||
|
@ -397,6 +407,9 @@ struct svc_program {
|
||||||
char * pg_class; /* class name: services sharing authentication */
|
char * pg_class; /* class name: services sharing authentication */
|
||||||
struct svc_stat * pg_stats; /* rpc statistics */
|
struct svc_stat * pg_stats; /* rpc statistics */
|
||||||
int (*pg_authenticate)(struct svc_rqst *);
|
int (*pg_authenticate)(struct svc_rqst *);
|
||||||
|
__be32 (*pg_init_request)(struct svc_rqst *,
|
||||||
|
const struct svc_program *,
|
||||||
|
struct svc_process_info *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -506,6 +519,9 @@ char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
|
||||||
struct kvec *first, void *p,
|
struct kvec *first, void *p,
|
||||||
size_t total);
|
size_t total);
|
||||||
__be32 svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
|
__be32 svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
|
||||||
|
__be32 svc_generic_init_request(struct svc_rqst *rqstp,
|
||||||
|
const struct svc_program *progp,
|
||||||
|
struct svc_process_info *procinfo);
|
||||||
|
|
||||||
#define RPC_MAX_ADDRBUFLEN (63U)
|
#define RPC_MAX_ADDRBUFLEN (63U)
|
||||||
|
|
||||||
|
|
115
net/sunrpc/svc.c
115
net/sunrpc/svc.c
|
@ -1160,6 +1160,59 @@ svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
|
||||||
return rpc_auth_ok;
|
return rpc_auth_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__be32
|
||||||
|
svc_generic_init_request(struct svc_rqst *rqstp,
|
||||||
|
const struct svc_program *progp,
|
||||||
|
struct svc_process_info *ret)
|
||||||
|
{
|
||||||
|
const struct svc_version *versp = NULL; /* compiler food */
|
||||||
|
const struct svc_procedure *procp = NULL;
|
||||||
|
|
||||||
|
if (rqstp->rq_vers >= progp->pg_nvers )
|
||||||
|
goto err_bad_vers;
|
||||||
|
versp = progp->pg_vers[rqstp->rq_vers];
|
||||||
|
if (!versp)
|
||||||
|
goto err_bad_vers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some protocol versions (namely NFSv4) require some form of
|
||||||
|
* congestion control. (See RFC 7530 section 3.1 paragraph 2)
|
||||||
|
* In other words, UDP is not allowed. We mark those when setting
|
||||||
|
* up the svc_xprt, and verify that here.
|
||||||
|
*
|
||||||
|
* The spec is not very clear about what error should be returned
|
||||||
|
* when someone tries to access a server that is listening on UDP
|
||||||
|
* for lower versions. RPC_PROG_MISMATCH seems to be the closest
|
||||||
|
* fit.
|
||||||
|
*/
|
||||||
|
if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
|
||||||
|
!test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
|
||||||
|
goto err_bad_vers;
|
||||||
|
|
||||||
|
if (rqstp->rq_proc >= versp->vs_nproc)
|
||||||
|
goto err_bad_proc;
|
||||||
|
rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
|
||||||
|
if (!procp)
|
||||||
|
goto err_bad_proc;
|
||||||
|
|
||||||
|
/* Initialize storage for argp and resp */
|
||||||
|
memset(rqstp->rq_argp, 0, procp->pc_argsize);
|
||||||
|
memset(rqstp->rq_resp, 0, procp->pc_ressize);
|
||||||
|
|
||||||
|
/* Bump per-procedure stats counter */
|
||||||
|
versp->vs_count[rqstp->rq_proc]++;
|
||||||
|
|
||||||
|
ret->dispatch = versp->vs_dispatch;
|
||||||
|
return rpc_success;
|
||||||
|
err_bad_vers:
|
||||||
|
ret->mismatch.lovers = progp->pg_lovers;
|
||||||
|
ret->mismatch.hivers = progp->pg_hivers;
|
||||||
|
return rpc_prog_mismatch;
|
||||||
|
err_bad_proc:
|
||||||
|
return rpc_proc_unavail;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(svc_generic_init_request);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common routine for processing the RPC request.
|
* Common routine for processing the RPC request.
|
||||||
*/
|
*/
|
||||||
|
@ -1167,11 +1220,11 @@ static int
|
||||||
svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
{
|
{
|
||||||
struct svc_program *progp;
|
struct svc_program *progp;
|
||||||
const struct svc_version *versp = NULL; /* compiler food */
|
|
||||||
const struct svc_procedure *procp = NULL;
|
const struct svc_procedure *procp = NULL;
|
||||||
struct svc_serv *serv = rqstp->rq_server;
|
struct svc_serv *serv = rqstp->rq_server;
|
||||||
|
struct svc_process_info process;
|
||||||
__be32 *statp;
|
__be32 *statp;
|
||||||
u32 prog, vers, proc;
|
u32 prog, vers;
|
||||||
__be32 auth_stat, rpc_stat;
|
__be32 auth_stat, rpc_stat;
|
||||||
int auth_res;
|
int auth_res;
|
||||||
__be32 *reply_statp;
|
__be32 *reply_statp;
|
||||||
|
@ -1203,8 +1256,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
svc_putnl(resv, 0); /* ACCEPT */
|
svc_putnl(resv, 0); /* ACCEPT */
|
||||||
|
|
||||||
rqstp->rq_prog = prog = svc_getnl(argv); /* program number */
|
rqstp->rq_prog = prog = svc_getnl(argv); /* program number */
|
||||||
rqstp->rq_vers = vers = svc_getnl(argv); /* version number */
|
rqstp->rq_vers = svc_getnl(argv); /* version number */
|
||||||
rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */
|
rqstp->rq_proc = svc_getnl(argv); /* procedure number */
|
||||||
|
|
||||||
for (progp = serv->sv_program; progp; progp = progp->pg_next)
|
for (progp = serv->sv_program; progp; progp = progp->pg_next)
|
||||||
if (prog == progp->pg_prog)
|
if (prog == progp->pg_prog)
|
||||||
|
@ -1242,29 +1295,22 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
if (progp == NULL)
|
if (progp == NULL)
|
||||||
goto err_bad_prog;
|
goto err_bad_prog;
|
||||||
|
|
||||||
if (vers >= progp->pg_nvers ||
|
rpc_stat = progp->pg_init_request(rqstp, progp, &process);
|
||||||
!(versp = progp->pg_vers[vers]))
|
switch (rpc_stat) {
|
||||||
|
case rpc_success:
|
||||||
|
break;
|
||||||
|
case rpc_prog_unavail:
|
||||||
|
goto err_bad_prog;
|
||||||
|
case rpc_prog_mismatch:
|
||||||
goto err_bad_vers;
|
goto err_bad_vers;
|
||||||
|
case rpc_proc_unavail:
|
||||||
/*
|
goto err_bad_proc;
|
||||||
* Some protocol versions (namely NFSv4) require some form of
|
}
|
||||||
* congestion control. (See RFC 7530 section 3.1 paragraph 2)
|
|
||||||
* In other words, UDP is not allowed. We mark those when setting
|
procp = rqstp->rq_procinfo;
|
||||||
* up the svc_xprt, and verify that here.
|
/* Should this check go into the dispatcher? */
|
||||||
*
|
if (!procp || !procp->pc_func)
|
||||||
* The spec is not very clear about what error should be returned
|
|
||||||
* when someone tries to access a server that is listening on UDP
|
|
||||||
* for lower versions. RPC_PROG_MISMATCH seems to be the closest
|
|
||||||
* fit.
|
|
||||||
*/
|
|
||||||
if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
|
|
||||||
!test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
|
|
||||||
goto err_bad_vers;
|
|
||||||
|
|
||||||
procp = versp->vs_proc + proc;
|
|
||||||
if (proc >= versp->vs_nproc || !procp->pc_func)
|
|
||||||
goto err_bad_proc;
|
goto err_bad_proc;
|
||||||
rqstp->rq_procinfo = procp;
|
|
||||||
|
|
||||||
/* Syntactic check complete */
|
/* Syntactic check complete */
|
||||||
serv->sv_stats->rpccnt++;
|
serv->sv_stats->rpccnt++;
|
||||||
|
@ -1274,13 +1320,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
statp = resv->iov_base +resv->iov_len;
|
statp = resv->iov_base +resv->iov_len;
|
||||||
svc_putnl(resv, RPC_SUCCESS);
|
svc_putnl(resv, RPC_SUCCESS);
|
||||||
|
|
||||||
/* Bump per-procedure stats counter */
|
|
||||||
versp->vs_count[proc]++;
|
|
||||||
|
|
||||||
/* Initialize storage for argp and resp */
|
|
||||||
memset(rqstp->rq_argp, 0, procp->pc_argsize);
|
|
||||||
memset(rqstp->rq_resp, 0, procp->pc_ressize);
|
|
||||||
|
|
||||||
/* un-reserve some of the out-queue now that we have a
|
/* un-reserve some of the out-queue now that we have a
|
||||||
* better idea of reply size
|
* better idea of reply size
|
||||||
*/
|
*/
|
||||||
|
@ -1288,7 +1327,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
|
svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
|
||||||
|
|
||||||
/* Call the function that processes the request. */
|
/* Call the function that processes the request. */
|
||||||
if (!versp->vs_dispatch) {
|
if (!process.dispatch) {
|
||||||
/*
|
/*
|
||||||
* Decode arguments
|
* Decode arguments
|
||||||
* XXX: why do we ignore the return value?
|
* XXX: why do we ignore the return value?
|
||||||
|
@ -1317,7 +1356,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dprintk("svc: calling dispatcher\n");
|
dprintk("svc: calling dispatcher\n");
|
||||||
if (!versp->vs_dispatch(rqstp, statp)) {
|
if (!process.dispatch(rqstp, statp)) {
|
||||||
/* Release reply info */
|
/* Release reply info */
|
||||||
if (procp->pc_release)
|
if (procp->pc_release)
|
||||||
procp->pc_release(rqstp);
|
procp->pc_release(rqstp);
|
||||||
|
@ -1386,16 +1425,16 @@ err_bad_prog:
|
||||||
|
|
||||||
err_bad_vers:
|
err_bad_vers:
|
||||||
svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
|
svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
|
||||||
vers, prog, progp->pg_name);
|
rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
|
||||||
|
|
||||||
serv->sv_stats->rpcbadfmt++;
|
serv->sv_stats->rpcbadfmt++;
|
||||||
svc_putnl(resv, RPC_PROG_MISMATCH);
|
svc_putnl(resv, RPC_PROG_MISMATCH);
|
||||||
svc_putnl(resv, progp->pg_lovers);
|
svc_putnl(resv, process.mismatch.lovers);
|
||||||
svc_putnl(resv, progp->pg_hivers);
|
svc_putnl(resv, process.mismatch.hivers);
|
||||||
goto sendit;
|
goto sendit;
|
||||||
|
|
||||||
err_bad_proc:
|
err_bad_proc:
|
||||||
svc_printk(rqstp, "unknown procedure (%d)\n", proc);
|
svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
|
||||||
|
|
||||||
serv->sv_stats->rpcbadfmt++;
|
serv->sv_stats->rpcbadfmt++;
|
||||||
svc_putnl(resv, RPC_PROC_UNAVAIL);
|
svc_putnl(resv, RPC_PROC_UNAVAIL);
|
||||||
|
|
Loading…
Add table
Reference in a new issue