Commit 5582863f authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker

SUNRPC: Add XDR overflow trace event

This can help field troubleshooting without needing the overhead of
a full network capture (ie, tcpdump).
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 0ccc61b1
...@@ -254,6 +254,73 @@ TRACE_EVENT(rpc_stats_latency, ...@@ -254,6 +254,73 @@ TRACE_EVENT(rpc_stats_latency,
__entry->backlog, __entry->rtt, __entry->execute) __entry->backlog, __entry->rtt, __entry->execute)
); );
TRACE_EVENT(rpc_xdr_overflow,
TP_PROTO(
const struct xdr_stream *xdr,
size_t requested
),
TP_ARGS(xdr, requested),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(int, version)
__field(size_t, requested)
__field(const void *, end)
__field(const void *, p)
__field(const void *, head_base)
__field(size_t, head_len)
__field(const void *, tail_base)
__field(size_t, tail_len)
__field(unsigned int, page_len)
__field(unsigned int, len)
__string(progname,
xdr->rqst->rq_task->tk_client->cl_program->name)
__string(procedure,
xdr->rqst->rq_task->tk_msg.rpc_proc->p_name)
),
TP_fast_assign(
if (xdr->rqst) {
const struct rpc_task *task = xdr->rqst->rq_task;
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
__assign_str(progname,
task->tk_client->cl_program->name)
__entry->version = task->tk_client->cl_vers;
__assign_str(procedure, task->tk_msg.rpc_proc->p_name)
} else {
__entry->task_id = 0;
__entry->client_id = 0;
__assign_str(progname, "unknown")
__entry->version = 0;
__assign_str(procedure, "unknown")
}
__entry->requested = requested;
__entry->end = xdr->end;
__entry->p = xdr->p;
__entry->head_base = xdr->buf->head[0].iov_base,
__entry->head_len = xdr->buf->head[0].iov_len,
__entry->page_len = xdr->buf->page_len,
__entry->tail_base = xdr->buf->tail[0].iov_base,
__entry->tail_len = xdr->buf->tail[0].iov_len,
__entry->len = xdr->buf->len;
),
TP_printk(
"task:%u@%u %sv%d %s requested=%zu p=%p end=%p xdr=[%p,%zu]/%u/[%p,%zu]/%u\n",
__entry->task_id, __entry->client_id,
__get_str(progname), __entry->version, __get_str(procedure),
__entry->requested, __entry->p, __entry->end,
__entry->head_base, __entry->head_len,
__entry->page_len,
__entry->tail_base, __entry->tail_len,
__entry->len
)
);
/* /*
* First define the enums in the below macros to be exported to userspace * First define the enums in the below macros to be exported to userspace
* via TRACE_DEFINE_ENUM(). * via TRACE_DEFINE_ENUM().
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/sunrpc/xdr.h> #include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/msg_prot.h>
#include <linux/bvec.h> #include <linux/bvec.h>
#include <trace/events/sunrpc.h>
/* /*
* XDR functions for basic NFS types * XDR functions for basic NFS types
...@@ -554,9 +555,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, ...@@ -554,9 +555,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
int frag1bytes, frag2bytes; int frag1bytes, frag2bytes;
if (nbytes > PAGE_SIZE) if (nbytes > PAGE_SIZE)
return NULL; /* Bigger buffers require special handling */ goto out_overflow; /* Bigger buffers require special handling */
if (xdr->buf->len + nbytes > xdr->buf->buflen) if (xdr->buf->len + nbytes > xdr->buf->buflen)
return NULL; /* Sorry, we're totally out of space */ goto out_overflow; /* Sorry, we're totally out of space */
frag1bytes = (xdr->end - xdr->p) << 2; frag1bytes = (xdr->end - xdr->p) << 2;
frag2bytes = nbytes - frag1bytes; frag2bytes = nbytes - frag1bytes;
if (xdr->iov) if (xdr->iov)
...@@ -585,6 +586,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, ...@@ -585,6 +586,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
xdr->buf->page_len += frag2bytes; xdr->buf->page_len += frag2bytes;
xdr->buf->len += nbytes; xdr->buf->len += nbytes;
return p; return p;
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
/** /**
...@@ -902,20 +906,23 @@ static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes) ...@@ -902,20 +906,23 @@ static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
size_t cplen = (char *)xdr->end - (char *)xdr->p; size_t cplen = (char *)xdr->end - (char *)xdr->p;
if (nbytes > xdr->scratch.iov_len) if (nbytes > xdr->scratch.iov_len)
return NULL; goto out_overflow;
p = __xdr_inline_decode(xdr, cplen); p = __xdr_inline_decode(xdr, cplen);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
memcpy(cpdest, p, cplen); memcpy(cpdest, p, cplen);
if (!xdr_set_next_buffer(xdr))
goto out_overflow;
cpdest += cplen; cpdest += cplen;
nbytes -= cplen; nbytes -= cplen;
if (!xdr_set_next_buffer(xdr))
return NULL;
p = __xdr_inline_decode(xdr, nbytes); p = __xdr_inline_decode(xdr, nbytes);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
memcpy(cpdest, p, nbytes); memcpy(cpdest, p, nbytes);
return xdr->scratch.iov_base; return xdr->scratch.iov_base;
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
/** /**
...@@ -932,14 +939,17 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) ...@@ -932,14 +939,17 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{ {
__be32 *p; __be32 *p;
if (nbytes == 0) if (unlikely(nbytes == 0))
return xdr->p; return xdr->p;
if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr)) if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
return NULL; goto out_overflow;
p = __xdr_inline_decode(xdr, nbytes); p = __xdr_inline_decode(xdr, nbytes);
if (p != NULL) if (p != NULL)
return p; return p;
return xdr_copy_to_scratch(xdr, nbytes); return xdr_copy_to_scratch(xdr, nbytes);
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
EXPORT_SYMBOL_GPL(xdr_inline_decode); EXPORT_SYMBOL_GPL(xdr_inline_decode);
......
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