Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f5667a5 authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker
Browse files

SUNRPC: Clean up rpc_verify_header()



- Recover some instruction count because I'm about to introduce a
  few xdr_inline_decode call sites
- Replace dprintk() call sites with trace points
- Reduce the hot path so it fits in fewer cachelines

I've also renamed it rpc_decode_header() to match everything else
in the RPC client.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent e8680a24
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -92,6 +92,9 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define	rpc_auth_gss	cpu_to_be32(RPC_AUTH_GSS)
#define	rpc_auth_gss	cpu_to_be32(RPC_AUTH_GSS)


#define	rpc_call	cpu_to_be32(RPC_CALL)
#define	rpc_call	cpu_to_be32(RPC_CALL)
#define	rpc_reply	cpu_to_be32(RPC_REPLY)

#define	rpc_msg_accepted	cpu_to_be32(RPC_MSG_ACCEPTED)


#define	rpc_success		cpu_to_be32(RPC_SUCCESS)
#define	rpc_success		cpu_to_be32(RPC_SUCCESS)
#define	rpc_prog_unavail	cpu_to_be32(RPC_PROG_UNAVAIL)
#define	rpc_prog_unavail	cpu_to_be32(RPC_PROG_UNAVAIL)
@@ -101,6 +104,9 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define	rpc_system_err		cpu_to_be32(RPC_SYSTEM_ERR)
#define	rpc_system_err		cpu_to_be32(RPC_SYSTEM_ERR)
#define	rpc_drop_reply		cpu_to_be32(RPC_DROP_REPLY)
#define	rpc_drop_reply		cpu_to_be32(RPC_DROP_REPLY)


#define	rpc_mismatch		cpu_to_be32(RPC_MISMATCH)
#define	rpc_auth_error		cpu_to_be32(RPC_AUTH_ERROR)

#define	rpc_auth_ok		cpu_to_be32(RPC_AUTH_OK)
#define	rpc_auth_ok		cpu_to_be32(RPC_AUTH_OK)
#define	rpc_autherr_badcred	cpu_to_be32(RPC_AUTH_BADCRED)
#define	rpc_autherr_badcred	cpu_to_be32(RPC_AUTH_BADCRED)
#define	rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED)
#define	rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED)
@@ -109,7 +115,6 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define	rpc_autherr_tooweak	cpu_to_be32(RPC_AUTH_TOOWEAK)
#define	rpc_autherr_tooweak	cpu_to_be32(RPC_AUTH_TOOWEAK)
#define	rpcsec_gsserr_credproblem	cpu_to_be32(RPCSEC_GSS_CREDPROBLEM)
#define	rpcsec_gsserr_credproblem	cpu_to_be32(RPCSEC_GSS_CREDPROBLEM)
#define	rpcsec_gsserr_ctxproblem	cpu_to_be32(RPCSEC_GSS_CTXPROBLEM)
#define	rpcsec_gsserr_ctxproblem	cpu_to_be32(RPCSEC_GSS_CTXPROBLEM)
#define	rpc_autherr_oldseqnum	cpu_to_be32(101)


/*
/*
 * Miscellaneous XDR helper functions
 * Miscellaneous XDR helper functions
+52 −0
Original line number Original line Diff line number Diff line
@@ -241,6 +241,58 @@ DECLARE_EVENT_CLASS(rpc_failure,
			TP_ARGS(task))
			TP_ARGS(task))


DEFINE_RPC_FAILURE(callhdr);
DEFINE_RPC_FAILURE(callhdr);
DEFINE_RPC_FAILURE(verifier);

DECLARE_EVENT_CLASS(rpc_reply_event,

	TP_PROTO(
		const struct rpc_task *task
	),

	TP_ARGS(task),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, xid)
		__string(progname, task->tk_client->cl_program->name)
		__field(u32, version)
		__string(procname, rpc_proc_name(task))
		__string(servername, task->tk_xprt->servername)
	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid);
		__assign_str(progname, task->tk_client->cl_program->name)
		__entry->version = task->tk_client->cl_vers;
		__assign_str(procname, rpc_proc_name(task))
		__assign_str(servername, task->tk_xprt->servername)
	),

	TP_printk("task:%u@%d server=%s xid=0x%08x %sv%d %s",
		__entry->task_id, __entry->client_id, __get_str(servername),
		__entry->xid, __get_str(progname), __entry->version,
		__get_str(procname))
)

#define DEFINE_RPC_REPLY_EVENT(name)					\
	DEFINE_EVENT(rpc_reply_event, rpc__##name,			\
			TP_PROTO(					\
				const struct rpc_task *task		\
			),						\
			TP_ARGS(task))

DEFINE_RPC_REPLY_EVENT(prog_unavail);
DEFINE_RPC_REPLY_EVENT(prog_mismatch);
DEFINE_RPC_REPLY_EVENT(proc_unavail);
DEFINE_RPC_REPLY_EVENT(garbage_args);
DEFINE_RPC_REPLY_EVENT(unparsable);
DEFINE_RPC_REPLY_EVENT(mismatch);
DEFINE_RPC_REPLY_EVENT(stale_creds);
DEFINE_RPC_REPLY_EVENT(bad_creds);
DEFINE_RPC_REPLY_EVENT(auth_tooweak);


TRACE_EVENT(rpc_stats_latency,
TRACE_EVENT(rpc_stats_latency,


+96 −127
Original line number Original line Diff line number Diff line
@@ -79,7 +79,7 @@ static void call_connect_status(struct rpc_task *task);


static int	rpc_encode_header(struct rpc_task *task,
static int	rpc_encode_header(struct rpc_task *task,
				  struct xdr_stream *xdr);
				  struct xdr_stream *xdr);
static __be32	*rpc_verify_header(struct rpc_task *task);
static __be32	*rpc_decode_header(struct rpc_task *task);
static int	rpc_ping(struct rpc_clnt *clnt);
static int	rpc_ping(struct rpc_clnt *clnt);


static void rpc_register_client(struct rpc_clnt *clnt)
static void rpc_register_client(struct rpc_clnt *clnt)
@@ -2292,7 +2292,7 @@ call_decode(struct rpc_task *task)
		goto out_retry;
		goto out_retry;
	}
	}


	p = rpc_verify_header(task);
	p = rpc_decode_header(task);
	if (IS_ERR(p)) {
	if (IS_ERR(p)) {
		if (p == ERR_PTR(-EAGAIN))
		if (p == ERR_PTR(-EAGAIN))
			goto out_retry;
			goto out_retry;
@@ -2308,7 +2308,7 @@ call_decode(struct rpc_task *task)
	return;
	return;
out_retry:
out_retry:
	task->tk_status = 0;
	task->tk_status = 0;
	/* Note: rpc_verify_header() may have freed the RPC slot */
	/* Note: rpc_decode_header() may have freed the RPC slot */
	if (task->tk_rqstp == req) {
	if (task->tk_rqstp == req) {
		xdr_free_bvec(&req->rq_rcv_buf);
		xdr_free_bvec(&req->rq_rcv_buf);
		req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
		req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
@@ -2347,164 +2347,133 @@ rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
	return error;
	return error;
}
}


static __be32 *
static noinline __be32 *
rpc_verify_header(struct rpc_task *task)
rpc_decode_header(struct rpc_task *task)
{
{
	struct rpc_clnt *clnt = task->tk_client;
	struct rpc_clnt *clnt = task->tk_client;
	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
	__be32	*p = iov->iov_base;
	__be32	*p = iov->iov_base;
	u32 n;
	int error = -EACCES;
	int error = -EACCES;


	if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
	/* RFC-1014 says that the representation of XDR data must be a
	/* RFC-1014 says that the representation of XDR data must be a
	 * multiple of four bytes
	 * multiple of four bytes
	 * - if it isn't pointer subtraction in the NFS client may give
	 * - if it isn't pointer subtraction in the NFS client may give
	 *   undefined results
	 *   undefined results
	 */
	 */
		dprintk("RPC: %5u %s: XDR representation not a multiple of"
	if (task->tk_rqstp->rq_rcv_buf.len & 3)
		       " 4 bytes: 0x%x\n", task->tk_pid, __func__,
		goto out_badlen;
		       task->tk_rqstp->rq_rcv_buf.len);
	if ((len -= 3) < 0)
		error = -EIO;
		goto out_unparsable;

	p++;	/* skip XID */
	if (*p++ != rpc_reply)
		goto out_unparsable;
	if (*p++ != rpc_msg_accepted)
		goto out_msg_denied;

	p = rpcauth_checkverf(task, p);
	if (IS_ERR(p))
		goto out_verifier;

	len = p - (__be32 *)iov->iov_base - 1;
	if (len < 0)
		goto out_unparsable;
	switch (*p++) {
	case rpc_success:
		return p;
	case rpc_prog_unavail:
		trace_rpc__prog_unavail(task);
		error = -EPFNOSUPPORT;
		goto out_err;
		goto out_err;
	case rpc_prog_mismatch:
		trace_rpc__prog_mismatch(task);
		error = -EPROTONOSUPPORT;
		goto out_err;
	case rpc_proc_unavail:
		trace_rpc__proc_unavail(task);
		error = -EOPNOTSUPP;
		goto out_err;
	case rpc_garbage_args:
		trace_rpc__garbage_args(task);
		break;
	default:
		trace_rpc__unparsable(task);
	}
	}
	if ((len -= 3) < 0)
		goto out_overflow;


	p += 1; /* skip XID */
out_garbage:
	if ((n = ntohl(*p++)) != RPC_REPLY) {
	clnt->cl_stats->rpcgarbage++;
		dprintk("RPC: %5u %s: not an RPC reply: %x\n",
	if (task->tk_garb_retry) {
			task->tk_pid, __func__, n);
		task->tk_garb_retry--;
		task->tk_action = call_encode;
		return ERR_PTR(-EAGAIN);
	}
out_err:
	rpc_exit(task, error);
	return ERR_PTR(error);

out_badlen:
	trace_rpc__unparsable(task);
	error = -EIO;
	goto out_err;

out_unparsable:
	trace_rpc__unparsable(task);
	error = -EIO;
	error = -EIO;
	goto out_garbage;
	goto out_garbage;
	}


	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
out_verifier:
		if (--len < 0)
	trace_rpc_bad_verifier(task);
			goto out_overflow;
	error = PTR_ERR(p);
		switch ((n = ntohl(*p++))) {
	goto out_garbage;
		case RPC_AUTH_ERROR:

out_msg_denied:
	switch (*p++) {
	case rpc_auth_error:
		break;
		break;
		case RPC_MISMATCH:
	case rpc_mismatch:
			dprintk("RPC: %5u %s: RPC call version mismatch!\n",
		trace_rpc__mismatch(task);
				task->tk_pid, __func__);
		error = -EPROTONOSUPPORT;
		error = -EPROTONOSUPPORT;
		goto out_err;
		goto out_err;
	default:
	default:
			dprintk("RPC: %5u %s: RPC call rejected, "
		trace_rpc__unparsable(task);
				"unknown error: %x\n",
				task->tk_pid, __func__, n);
		error = -EIO;
		error = -EIO;
		goto out_err;
		goto out_err;
	}
	}
		if (--len < 0)

			goto out_overflow;
	switch (*p++) {
		switch ((n = ntohl(*p++))) {
	case rpc_autherr_rejectedcred:
		case RPC_AUTH_REJECTEDCRED:
	case rpc_autherr_rejectedverf:
		case RPC_AUTH_REJECTEDVERF:
	case rpcsec_gsserr_credproblem:
		case RPCSEC_GSS_CREDPROBLEM:
	case rpcsec_gsserr_ctxproblem:
		case RPCSEC_GSS_CTXPROBLEM:
		if (!task->tk_cred_retry)
		if (!task->tk_cred_retry)
			break;
			break;
		task->tk_cred_retry--;
		task->tk_cred_retry--;
			dprintk("RPC: %5u %s: retry stale creds\n",
		trace_rpc__stale_creds(task);
					task->tk_pid, __func__);
		rpcauth_invalcred(task);
		rpcauth_invalcred(task);
		/* Ensure we obtain a new XID! */
		/* Ensure we obtain a new XID! */
		xprt_release(task);
		xprt_release(task);
		task->tk_action = call_reserve;
		task->tk_action = call_reserve;
			goto out_retry;
		return ERR_PTR(-EAGAIN);
		case RPC_AUTH_BADCRED:
	case rpc_autherr_badcred:
		case RPC_AUTH_BADVERF:
	case rpc_autherr_badverf:
		/* possibly garbled cred/verf? */
		/* possibly garbled cred/verf? */
		if (!task->tk_garb_retry)
		if (!task->tk_garb_retry)
			break;
			break;
		task->tk_garb_retry--;
		task->tk_garb_retry--;
			dprintk("RPC: %5u %s: retry garbled creds\n",
		trace_rpc__bad_creds(task);
					task->tk_pid, __func__);
		task->tk_action = call_encode;
		task->tk_action = call_encode;
			goto out_retry;
		return ERR_PTR(-EAGAIN);
		case RPC_AUTH_TOOWEAK:
	case rpc_autherr_tooweak:
			printk(KERN_NOTICE "RPC: server %s requires stronger "
		trace_rpc__auth_tooweak(task);
			       "authentication.\n",
		pr_warn("RPC: server %s requires stronger authentication.\n",
			task->tk_xprt->servername);
			task->tk_xprt->servername);
		break;
		break;
	default:
	default:
			dprintk("RPC: %5u %s: unknown auth error: %x\n",
		trace_rpc__unparsable(task);
					task->tk_pid, __func__, n);
		error = -EIO;
		error = -EIO;
	}
	}
		dprintk("RPC: %5u %s: call rejected %d\n",
				task->tk_pid, __func__, n);
		goto out_err;
	}
	p = rpcauth_checkverf(task, p);
	if (IS_ERR(p)) {
		error = PTR_ERR(p);
		dprintk("RPC: %5u %s: auth check failed with %d\n",
				task->tk_pid, __func__, error);
		goto out_garbage;		/* bad verifier, retry */
	}
	len = p - (__be32 *)iov->iov_base - 1;
	if (len < 0)
		goto out_overflow;
	switch ((n = ntohl(*p++))) {
	case RPC_SUCCESS:
		return p;
	case RPC_PROG_UNAVAIL:
		dprintk("RPC: %5u %s: program %u is unsupported "
				"by server %s\n", task->tk_pid, __func__,
				(unsigned int)clnt->cl_prog,
				task->tk_xprt->servername);
		error = -EPFNOSUPPORT;
		goto out_err;
	case RPC_PROG_MISMATCH:
		dprintk("RPC: %5u %s: program %u, version %u unsupported "
				"by server %s\n", task->tk_pid, __func__,
				(unsigned int)clnt->cl_prog,
				(unsigned int)clnt->cl_vers,
				task->tk_xprt->servername);
		error = -EPROTONOSUPPORT;
	goto out_err;
	goto out_err;
	case RPC_PROC_UNAVAIL:
		dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
				"version %u on server %s\n",
				task->tk_pid, __func__,
				rpc_proc_name(task),
				clnt->cl_prog, clnt->cl_vers,
				task->tk_xprt->servername);
		error = -EOPNOTSUPP;
		goto out_err;
	case RPC_GARBAGE_ARGS:
		dprintk("RPC: %5u %s: server saw garbage\n",
				task->tk_pid, __func__);
		break;			/* retry */
	default:
		dprintk("RPC: %5u %s: server accept status: %x\n",
				task->tk_pid, __func__, n);
		/* Also retry */
	}

out_garbage:
	clnt->cl_stats->rpcgarbage++;
	if (task->tk_garb_retry) {
		task->tk_garb_retry--;
		dprintk("RPC: %5u %s: retrying\n",
				task->tk_pid, __func__);
		task->tk_action = call_encode;
out_retry:
		return ERR_PTR(-EAGAIN);
	}
out_err:
	rpc_exit(task, error);
	dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
			__func__, error);
	return ERR_PTR(error);
out_overflow:
	dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
			__func__);
	goto out_garbage;
}
}


static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,