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

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
...@@ -92,6 +92,9 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) ...@@ -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) ...@@ -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) ...@@ -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
......
...@@ -241,6 +241,58 @@ DECLARE_EVENT_CLASS(rpc_failure, ...@@ -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,
......
...@@ -79,7 +79,7 @@ static void call_connect_status(struct rpc_task *task); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment