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 */
*/ if (task->tk_rqstp->rq_rcv_buf.len & 3)
dprintk("RPC: %5u %s: XDR representation not a multiple of" goto out_badlen;
" 4 bytes: 0x%x\n", task->tk_pid, __func__,
task->tk_rqstp->rq_rcv_buf.len);
error = -EIO;
goto out_err;
}
if ((len -= 3) < 0) if ((len -= 3) < 0)
goto out_overflow; goto out_unparsable;
p += 1; /* skip XID */ p++; /* skip XID */
if ((n = ntohl(*p++)) != RPC_REPLY) { if (*p++ != rpc_reply)
dprintk("RPC: %5u %s: not an RPC reply: %x\n", goto out_unparsable;
task->tk_pid, __func__, n); if (*p++ != rpc_msg_accepted)
error = -EIO; goto out_msg_denied;
goto out_garbage;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
if (--len < 0)
goto out_overflow;
switch ((n = ntohl(*p++))) {
case RPC_AUTH_ERROR:
break;
case RPC_MISMATCH:
dprintk("RPC: %5u %s: RPC call version mismatch!\n",
task->tk_pid, __func__);
error = -EPROTONOSUPPORT;
goto out_err;
default:
dprintk("RPC: %5u %s: RPC call rejected, "
"unknown error: %x\n",
task->tk_pid, __func__, n);
error = -EIO;
goto out_err;
}
if (--len < 0)
goto out_overflow;
switch ((n = ntohl(*p++))) {
case RPC_AUTH_REJECTEDCRED:
case RPC_AUTH_REJECTEDVERF:
case RPCSEC_GSS_CREDPROBLEM:
case RPCSEC_GSS_CTXPROBLEM:
if (!task->tk_cred_retry)
break;
task->tk_cred_retry--;
dprintk("RPC: %5u %s: retry stale creds\n",
task->tk_pid, __func__);
rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
task->tk_action = call_reserve;
goto out_retry;
case RPC_AUTH_BADCRED:
case RPC_AUTH_BADVERF:
/* possibly garbled cred/verf? */
if (!task->tk_garb_retry)
break;
task->tk_garb_retry--;
dprintk("RPC: %5u %s: retry garbled creds\n",
task->tk_pid, __func__);
task->tk_action = call_encode;
goto out_retry;
case RPC_AUTH_TOOWEAK:
printk(KERN_NOTICE "RPC: server %s requires stronger "
"authentication.\n",
task->tk_xprt->servername);
break;
default:
dprintk("RPC: %5u %s: unknown auth error: %x\n",
task->tk_pid, __func__, n);
error = -EIO;
}
dprintk("RPC: %5u %s: call rejected %d\n",
task->tk_pid, __func__, n);
goto out_err;
}
p = rpcauth_checkverf(task, p); p = rpcauth_checkverf(task, p);
if (IS_ERR(p)) { if (IS_ERR(p))
error = PTR_ERR(p); goto out_verifier;
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; len = p - (__be32 *)iov->iov_base - 1;
if (len < 0) if (len < 0)
goto out_overflow; goto out_unparsable;
switch ((n = ntohl(*p++))) { switch (*p++) {
case RPC_SUCCESS: case rpc_success:
return p; return p;
case RPC_PROG_UNAVAIL: case rpc_prog_unavail:
dprintk("RPC: %5u %s: program %u is unsupported " trace_rpc__prog_unavail(task);
"by server %s\n", task->tk_pid, __func__,
(unsigned int)clnt->cl_prog,
task->tk_xprt->servername);
error = -EPFNOSUPPORT; error = -EPFNOSUPPORT;
goto out_err; goto out_err;
case RPC_PROG_MISMATCH: case rpc_prog_mismatch:
dprintk("RPC: %5u %s: program %u, version %u unsupported " trace_rpc__prog_mismatch(task);
"by server %s\n", task->tk_pid, __func__,
(unsigned int)clnt->cl_prog,
(unsigned int)clnt->cl_vers,
task->tk_xprt->servername);
error = -EPROTONOSUPPORT; error = -EPROTONOSUPPORT;
goto out_err; goto out_err;
case RPC_PROC_UNAVAIL: case rpc_proc_unavail:
dprintk("RPC: %5u %s: proc %s unsupported by program %u, " trace_rpc__proc_unavail(task);
"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; error = -EOPNOTSUPP;
goto out_err; goto out_err;
case RPC_GARBAGE_ARGS: case rpc_garbage_args:
dprintk("RPC: %5u %s: server saw garbage\n", trace_rpc__garbage_args(task);
task->tk_pid, __func__); break;
break; /* retry */
default: default:
dprintk("RPC: %5u %s: server accept status: %x\n", trace_rpc__unparsable(task);
task->tk_pid, __func__, n);
/* Also retry */
} }
out_garbage: out_garbage:
clnt->cl_stats->rpcgarbage++; clnt->cl_stats->rpcgarbage++;
if (task->tk_garb_retry) { if (task->tk_garb_retry) {
task->tk_garb_retry--; task->tk_garb_retry--;
dprintk("RPC: %5u %s: retrying\n",
task->tk_pid, __func__);
task->tk_action = call_encode; task->tk_action = call_encode;
out_retry:
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
} }
out_err: out_err:
rpc_exit(task, error); rpc_exit(task, error);
dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
__func__, error);
return ERR_PTR(error); return ERR_PTR(error);
out_overflow:
dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid, out_badlen:
__func__); trace_rpc__unparsable(task);
error = -EIO;
goto out_err;
out_unparsable:
trace_rpc__unparsable(task);
error = -EIO;
goto out_garbage; goto out_garbage;
out_verifier:
trace_rpc_bad_verifier(task);
error = PTR_ERR(p);
goto out_garbage;
out_msg_denied:
switch (*p++) {
case rpc_auth_error:
break;
case rpc_mismatch:
trace_rpc__mismatch(task);
error = -EPROTONOSUPPORT;
goto out_err;
default:
trace_rpc__unparsable(task);
error = -EIO;
goto out_err;
}
switch (*p++) {
case rpc_autherr_rejectedcred:
case rpc_autherr_rejectedverf:
case rpcsec_gsserr_credproblem:
case rpcsec_gsserr_ctxproblem:
if (!task->tk_cred_retry)
break;
task->tk_cred_retry--;
trace_rpc__stale_creds(task);
rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
task->tk_action = call_reserve;
return ERR_PTR(-EAGAIN);
case rpc_autherr_badcred:
case rpc_autherr_badverf:
/* possibly garbled cred/verf? */
if (!task->tk_garb_retry)
break;
task->tk_garb_retry--;
trace_rpc__bad_creds(task);
task->tk_action = call_encode;
return ERR_PTR(-EAGAIN);
case rpc_autherr_tooweak:
trace_rpc__auth_tooweak(task);
pr_warn("RPC: server %s requires stronger authentication.\n",
task->tk_xprt->servername);
break;
default:
trace_rpc__unparsable(task);
error = -EIO;
}
goto out_err;
} }
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