Skip to content

Commit 7be9cea

Browse files
chuckleveramschuma-ntap
authored andcommitted
SUNRPC: Add trace event that reports reply page vector alignment
We don't want READ payloads that are partially in the head iovec and in the page buffer because this requires pull-up, which can be expensive. The NFS/RPC client tries hard to predict the size of the head iovec so that the incoming READ data payload lands only in the page vector, but it doesn't always get it right. To help diagnose such problems, add a trace point in the logic that decodes READ-like operations that reports whether pull-up is being done. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent 5582863 commit 7be9cea

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

include/trace/events/sunrpc.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,65 @@ TRACE_EVENT(rpc_xdr_overflow,
321321
)
322322
);
323323

324+
TRACE_EVENT(rpc_xdr_alignment,
325+
TP_PROTO(
326+
const struct xdr_stream *xdr,
327+
size_t offset,
328+
unsigned int copied
329+
),
330+
331+
TP_ARGS(xdr, offset, copied),
332+
333+
TP_STRUCT__entry(
334+
__field(unsigned int, task_id)
335+
__field(unsigned int, client_id)
336+
__field(int, version)
337+
__field(size_t, offset)
338+
__field(unsigned int, copied)
339+
__field(const void *, head_base)
340+
__field(size_t, head_len)
341+
__field(const void *, tail_base)
342+
__field(size_t, tail_len)
343+
__field(unsigned int, page_len)
344+
__field(unsigned int, len)
345+
__string(progname,
346+
xdr->rqst->rq_task->tk_client->cl_program->name)
347+
__string(procedure,
348+
xdr->rqst->rq_task->tk_msg.rpc_proc->p_name)
349+
),
350+
351+
TP_fast_assign(
352+
const struct rpc_task *task = xdr->rqst->rq_task;
353+
354+
__entry->task_id = task->tk_pid;
355+
__entry->client_id = task->tk_client->cl_clid;
356+
__assign_str(progname,
357+
task->tk_client->cl_program->name)
358+
__entry->version = task->tk_client->cl_vers;
359+
__assign_str(procedure, task->tk_msg.rpc_proc->p_name)
360+
361+
__entry->offset = offset;
362+
__entry->copied = copied;
363+
__entry->head_base = xdr->buf->head[0].iov_base,
364+
__entry->head_len = xdr->buf->head[0].iov_len,
365+
__entry->page_len = xdr->buf->page_len,
366+
__entry->tail_base = xdr->buf->tail[0].iov_base,
367+
__entry->tail_len = xdr->buf->tail[0].iov_len,
368+
__entry->len = xdr->buf->len;
369+
),
370+
371+
TP_printk(
372+
"task:%u@%u %sv%d %s offset=%zu copied=%u xdr=[%p,%zu]/%u/[%p,%zu]/%u\n",
373+
__entry->task_id, __entry->client_id,
374+
__get_str(progname), __entry->version, __get_str(procedure),
375+
__entry->offset, __entry->copied,
376+
__entry->head_base, __entry->head_len,
377+
__entry->page_len,
378+
__entry->tail_base, __entry->tail_len,
379+
__entry->len
380+
)
381+
);
382+
324383
/*
325384
* First define the enums in the below macros to be exported to userspace
326385
* via TRACE_DEFINE_ENUM().

net/sunrpc/xdr.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,15 @@ EXPORT_SYMBOL_GPL(_copy_from_pages);
347347
* 'len' bytes. The extra data is not lost, but is instead
348348
* moved into the inlined pages and/or the tail.
349349
*/
350-
static void
350+
static unsigned int
351351
xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
352352
{
353353
struct kvec *head, *tail;
354354
size_t copy, offs;
355355
unsigned int pglen = buf->page_len;
356+
unsigned int result;
356357

358+
result = 0;
357359
tail = buf->tail;
358360
head = buf->head;
359361

@@ -367,6 +369,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
367369
copy = tail->iov_len - len;
368370
memmove((char *)tail->iov_base + len,
369371
tail->iov_base, copy);
372+
result += copy;
370373
}
371374
/* Copy from the inlined pages into the tail */
372375
copy = len;
@@ -377,11 +380,13 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
377380
copy = 0;
378381
else if (copy > tail->iov_len - offs)
379382
copy = tail->iov_len - offs;
380-
if (copy != 0)
383+
if (copy != 0) {
381384
_copy_from_pages((char *)tail->iov_base + offs,
382385
buf->pages,
383386
buf->page_base + pglen + offs - len,
384387
copy);
388+
result += copy;
389+
}
385390
/* Do we also need to copy data from the head into the tail ? */
386391
if (len > pglen) {
387392
offs = copy = len - pglen;
@@ -391,6 +396,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
391396
(char *)head->iov_base +
392397
head->iov_len - offs,
393398
copy);
399+
result += copy;
394400
}
395401
}
396402
/* Now handle pages */
@@ -406,12 +412,15 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
406412
_copy_to_pages(buf->pages, buf->page_base,
407413
(char *)head->iov_base + head->iov_len - len,
408414
copy);
415+
result += copy;
409416
}
410417
head->iov_len -= len;
411418
buf->buflen -= len;
412419
/* Have we truncated the message? */
413420
if (buf->len > buf->buflen)
414421
buf->len = buf->buflen;
422+
423+
return result;
415424
}
416425

417426
/**
@@ -423,14 +432,16 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
423432
* 'len' bytes. The extra data is not lost, but is instead
424433
* moved into the tail.
425434
*/
426-
static void
435+
static unsigned int
427436
xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
428437
{
429438
struct kvec *tail;
430439
size_t copy;
431440
unsigned int pglen = buf->page_len;
432441
unsigned int tailbuf_len;
442+
unsigned int result;
433443

444+
result = 0;
434445
tail = buf->tail;
435446
BUG_ON (len > pglen);
436447

@@ -448,18 +459,22 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
448459
if (tail->iov_len > len) {
449460
char *p = (char *)tail->iov_base + len;
450461
memmove(p, tail->iov_base, tail->iov_len - len);
462+
result += tail->iov_len - len;
451463
} else
452464
copy = tail->iov_len;
453465
/* Copy from the inlined pages into the tail */
454466
_copy_from_pages((char *)tail->iov_base,
455467
buf->pages, buf->page_base + pglen - len,
456468
copy);
469+
result += copy;
457470
}
458471
buf->page_len -= len;
459472
buf->buflen -= len;
460473
/* Have we truncated the message? */
461474
if (buf->len > buf->buflen)
462475
buf->len = buf->buflen;
476+
477+
return result;
463478
}
464479

465480
void
@@ -959,13 +974,17 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
959974
struct kvec *iov;
960975
unsigned int nwords = XDR_QUADLEN(len);
961976
unsigned int cur = xdr_stream_pos(xdr);
977+
unsigned int copied, offset;
962978

963979
if (xdr->nwords == 0)
964980
return 0;
981+
965982
/* Realign pages to current pointer position */
966-
iov = buf->head;
983+
iov = buf->head;
967984
if (iov->iov_len > cur) {
968-
xdr_shrink_bufhead(buf, iov->iov_len - cur);
985+
offset = iov->iov_len - cur;
986+
copied = xdr_shrink_bufhead(buf, offset);
987+
trace_rpc_xdr_alignment(xdr, offset, copied);
969988
xdr->nwords = XDR_QUADLEN(buf->len - cur);
970989
}
971990

@@ -977,7 +996,9 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
977996
len = buf->page_len;
978997
else if (nwords < xdr->nwords) {
979998
/* Truncate page data and move it into the tail */
980-
xdr_shrink_pagelen(buf, buf->page_len - len);
999+
offset = buf->page_len - len;
1000+
copied = xdr_shrink_pagelen(buf, offset);
1001+
trace_rpc_xdr_alignment(xdr, offset, copied);
9811002
xdr->nwords = XDR_QUADLEN(buf->len - cur);
9821003
}
9831004
return len;

0 commit comments

Comments
 (0)