mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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_class		= "nfsd",		/* share authentication with nfsd */
 | 
			
		||||
	.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_stats = &nfs4_callback_stats,
 | 
			
		||||
	.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_stats		= &nfsd_acl_svcstats,
 | 
			
		||||
	.pg_authenticate	= &svc_set_client,
 | 
			
		||||
	.pg_init_request	= svc_generic_init_request,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct svc_stat	nfsd_acl_svcstats = {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +119,7 @@ struct svc_program		nfsd_program = {
 | 
			
		|||
	.pg_class		= "nfsd",		/* authentication class */
 | 
			
		||||
	.pg_stats		= &nfsd_svcstats,	/* version table */
 | 
			
		||||
	.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];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -397,6 +407,9 @@ struct svc_program {
 | 
			
		|||
	char *			pg_class;	/* class name: services sharing authentication */
 | 
			
		||||
	struct svc_stat *	pg_stats;	/* rpc statistics */
 | 
			
		||||
	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,
 | 
			
		||||
					     size_t total);
 | 
			
		||||
__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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__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.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1167,11 +1220,11 @@ static int
 | 
			
		|||
svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 | 
			
		||||
{
 | 
			
		||||
	struct svc_program	*progp;
 | 
			
		||||
	const struct svc_version *versp = NULL;	/* compiler food */
 | 
			
		||||
	const struct svc_procedure *procp = NULL;
 | 
			
		||||
	struct svc_serv		*serv = rqstp->rq_server;
 | 
			
		||||
	struct svc_process_info process;
 | 
			
		||||
	__be32			*statp;
 | 
			
		||||
	u32			prog, vers, proc;
 | 
			
		||||
	u32			prog, vers;
 | 
			
		||||
	__be32			auth_stat, rpc_stat;
 | 
			
		||||
	int			auth_res;
 | 
			
		||||
	__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 */
 | 
			
		||||
 | 
			
		||||
	rqstp->rq_prog = prog = svc_getnl(argv);	/* program number */
 | 
			
		||||
	rqstp->rq_vers = vers = svc_getnl(argv);	/* version number */
 | 
			
		||||
	rqstp->rq_proc = proc = svc_getnl(argv);	/* procedure number */
 | 
			
		||||
	rqstp->rq_vers = svc_getnl(argv);	/* version number */
 | 
			
		||||
	rqstp->rq_proc = svc_getnl(argv);	/* procedure number */
 | 
			
		||||
 | 
			
		||||
	for (progp = serv->sv_program; progp; progp = progp->pg_next)
 | 
			
		||||
		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)
 | 
			
		||||
		goto err_bad_prog;
 | 
			
		||||
 | 
			
		||||
	if (vers >= progp->pg_nvers ||
 | 
			
		||||
	  !(versp = progp->pg_vers[vers]))
 | 
			
		||||
	rpc_stat = progp->pg_init_request(rqstp, progp, &process);
 | 
			
		||||
	switch (rpc_stat) {
 | 
			
		||||
	case rpc_success:
 | 
			
		||||
		break;
 | 
			
		||||
	case rpc_prog_unavail:
 | 
			
		||||
		goto err_bad_prog;
 | 
			
		||||
	case rpc_prog_mismatch:
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
	procp = versp->vs_proc + proc;
 | 
			
		||||
	if (proc >= versp->vs_nproc || !procp->pc_func)
 | 
			
		||||
	case rpc_proc_unavail:
 | 
			
		||||
		goto err_bad_proc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	procp = rqstp->rq_procinfo;
 | 
			
		||||
	/* Should this check go into the dispatcher? */
 | 
			
		||||
	if (!procp || !procp->pc_func)
 | 
			
		||||
		goto err_bad_proc;
 | 
			
		||||
	rqstp->rq_procinfo = procp;
 | 
			
		||||
 | 
			
		||||
	/* Syntactic check complete */
 | 
			
		||||
	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;
 | 
			
		||||
	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
 | 
			
		||||
	 * 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);
 | 
			
		||||
 | 
			
		||||
	/* Call the function that processes the request. */
 | 
			
		||||
	if (!versp->vs_dispatch) {
 | 
			
		||||
	if (!process.dispatch) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Decode arguments
 | 
			
		||||
		 * 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 {
 | 
			
		||||
		dprintk("svc: calling dispatcher\n");
 | 
			
		||||
		if (!versp->vs_dispatch(rqstp, statp)) {
 | 
			
		||||
		if (!process.dispatch(rqstp, statp)) {
 | 
			
		||||
			/* Release reply info */
 | 
			
		||||
			if (procp->pc_release)
 | 
			
		||||
				procp->pc_release(rqstp);
 | 
			
		||||
| 
						 | 
				
			
			@ -1386,16 +1425,16 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 | 
			
		|||
 | 
			
		||||
err_bad_vers:
 | 
			
		||||
	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++;
 | 
			
		||||
	svc_putnl(resv, RPC_PROG_MISMATCH);
 | 
			
		||||
	svc_putnl(resv, progp->pg_lovers);
 | 
			
		||||
	svc_putnl(resv, progp->pg_hivers);
 | 
			
		||||
	svc_putnl(resv, process.mismatch.lovers);
 | 
			
		||||
	svc_putnl(resv, process.mismatch.hivers);
 | 
			
		||||
	goto sendit;
 | 
			
		||||
 | 
			
		||||
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++;
 | 
			
		||||
	svc_putnl(resv, RPC_PROC_UNAVAIL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue