diff options
author | Jeff Layton <jlayton@primarydata.com> | 2014-11-21 14:19:31 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-12-09 11:29:14 -0500 |
commit | 83a712e0afefaf68555f816ea78ecd2862c6cf30 (patch) | |
tree | 05e25469b98a7f437209ea0a50580d7f291c3d90 | |
parent | b1691bc03d4eddb959234409167bef9be9e62d74 (diff) |
sunrpc: add some tracepoints around enqueue and dequeue of svc_xprt
These were useful when I was tracking down a race condition between
svc_xprt_do_enqueue and svc_get_next_xprt.
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | include/trace/events/sunrpc.h | 94 | ||||
-rw-r--r-- | net/sunrpc/svc_xprt.c | 22 |
2 files changed, 109 insertions, 7 deletions
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index ee4438a63a48..b9c1dc6c825a 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/sunrpc/clnt.h> | 8 | #include <linux/sunrpc/clnt.h> |
9 | #include <linux/sunrpc/svc.h> | 9 | #include <linux/sunrpc/svc.h> |
10 | #include <linux/sunrpc/xprtsock.h> | 10 | #include <linux/sunrpc/xprtsock.h> |
11 | #include <linux/sunrpc/svc_xprt.h> | ||
11 | #include <net/tcp_states.h> | 12 | #include <net/tcp_states.h> |
12 | #include <linux/net.h> | 13 | #include <linux/net.h> |
13 | #include <linux/tracepoint.h> | 14 | #include <linux/tracepoint.h> |
@@ -480,6 +481,99 @@ DEFINE_EVENT(svc_rqst_status, svc_send, | |||
480 | TP_PROTO(struct svc_rqst *rqst, int status), | 481 | TP_PROTO(struct svc_rqst *rqst, int status), |
481 | TP_ARGS(rqst, status)); | 482 | TP_ARGS(rqst, status)); |
482 | 483 | ||
484 | #define show_svc_xprt_flags(flags) \ | ||
485 | __print_flags(flags, "|", \ | ||
486 | { (1UL << XPT_BUSY), "XPT_BUSY"}, \ | ||
487 | { (1UL << XPT_CONN), "XPT_CONN"}, \ | ||
488 | { (1UL << XPT_CLOSE), "XPT_CLOSE"}, \ | ||
489 | { (1UL << XPT_DATA), "XPT_DATA"}, \ | ||
490 | { (1UL << XPT_TEMP), "XPT_TEMP"}, \ | ||
491 | { (1UL << XPT_DEAD), "XPT_DEAD"}, \ | ||
492 | { (1UL << XPT_CHNGBUF), "XPT_CHNGBUF"}, \ | ||
493 | { (1UL << XPT_DEFERRED), "XPT_DEFERRED"}, \ | ||
494 | { (1UL << XPT_OLD), "XPT_OLD"}, \ | ||
495 | { (1UL << XPT_LISTENER), "XPT_LISTENER"}, \ | ||
496 | { (1UL << XPT_CACHE_AUTH), "XPT_CACHE_AUTH"}, \ | ||
497 | { (1UL << XPT_LOCAL), "XPT_LOCAL"}) | ||
498 | |||
499 | TRACE_EVENT(svc_xprt_do_enqueue, | ||
500 | TP_PROTO(struct svc_xprt *xprt, struct svc_rqst *rqst), | ||
501 | |||
502 | TP_ARGS(xprt, rqst), | ||
503 | |||
504 | TP_STRUCT__entry( | ||
505 | __field(struct svc_xprt *, xprt) | ||
506 | __field(struct svc_rqst *, rqst) | ||
507 | ), | ||
508 | |||
509 | TP_fast_assign( | ||
510 | __entry->xprt = xprt; | ||
511 | __entry->rqst = rqst; | ||
512 | ), | ||
513 | |||
514 | TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt, | ||
515 | (struct sockaddr *)&__entry->xprt->xpt_remote, | ||
516 | __entry->rqst ? __entry->rqst->rq_task->pid : 0, | ||
517 | show_svc_xprt_flags(__entry->xprt->xpt_flags)) | ||
518 | ); | ||
519 | |||
520 | TRACE_EVENT(svc_xprt_dequeue, | ||
521 | TP_PROTO(struct svc_xprt *xprt), | ||
522 | |||
523 | TP_ARGS(xprt), | ||
524 | |||
525 | TP_STRUCT__entry( | ||
526 | __field(struct svc_xprt *, xprt) | ||
527 | __field_struct(struct sockaddr_storage, ss) | ||
528 | __field(unsigned long, flags) | ||
529 | ), | ||
530 | |||
531 | TP_fast_assign( | ||
532 | __entry->xprt = xprt, | ||
533 | xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss)); | ||
534 | __entry->flags = xprt ? xprt->xpt_flags : 0; | ||
535 | ), | ||
536 | |||
537 | TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt, | ||
538 | (struct sockaddr *)&__entry->ss, | ||
539 | show_svc_xprt_flags(__entry->flags)) | ||
540 | ); | ||
541 | |||
542 | TRACE_EVENT(svc_wake_up, | ||
543 | TP_PROTO(int pid), | ||
544 | |||
545 | TP_ARGS(pid), | ||
546 | |||
547 | TP_STRUCT__entry( | ||
548 | __field(int, pid) | ||
549 | ), | ||
550 | |||
551 | TP_fast_assign( | ||
552 | __entry->pid = pid; | ||
553 | ), | ||
554 | |||
555 | TP_printk("pid=%d", __entry->pid) | ||
556 | ); | ||
557 | |||
558 | TRACE_EVENT(svc_handle_xprt, | ||
559 | TP_PROTO(struct svc_xprt *xprt, int len), | ||
560 | |||
561 | TP_ARGS(xprt, len), | ||
562 | |||
563 | TP_STRUCT__entry( | ||
564 | __field(struct svc_xprt *, xprt) | ||
565 | __field(int, len) | ||
566 | ), | ||
567 | |||
568 | TP_fast_assign( | ||
569 | __entry->xprt = xprt; | ||
570 | __entry->len = len; | ||
571 | ), | ||
572 | |||
573 | TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt, | ||
574 | (struct sockaddr *)&__entry->xprt->xpt_remote, __entry->len, | ||
575 | show_svc_xprt_flags(__entry->xprt->xpt_flags)) | ||
576 | ); | ||
483 | #endif /* _TRACE_SUNRPC_H */ | 577 | #endif /* _TRACE_SUNRPC_H */ |
484 | 578 | ||
485 | #include <trace/define_trace.h> | 579 | #include <trace/define_trace.h> |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index ed90d955f733..73d40bd1839a 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -322,12 +322,12 @@ static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) | |||
322 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt) | 322 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt) |
323 | { | 323 | { |
324 | struct svc_pool *pool; | 324 | struct svc_pool *pool; |
325 | struct svc_rqst *rqstp; | 325 | struct svc_rqst *rqstp = NULL; |
326 | int cpu; | 326 | int cpu; |
327 | bool queued = false; | 327 | bool queued = false; |
328 | 328 | ||
329 | if (!svc_xprt_has_something_to_do(xprt)) | 329 | if (!svc_xprt_has_something_to_do(xprt)) |
330 | return; | 330 | goto out; |
331 | 331 | ||
332 | /* Mark transport as busy. It will remain in this state until | 332 | /* Mark transport as busy. It will remain in this state until |
333 | * the provider calls svc_xprt_received. We update XPT_BUSY | 333 | * the provider calls svc_xprt_received. We update XPT_BUSY |
@@ -337,7 +337,7 @@ static void svc_xprt_do_enqueue(struct svc_xprt *xprt) | |||
337 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) { | 337 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) { |
338 | /* Don't enqueue transport while already enqueued */ | 338 | /* Don't enqueue transport while already enqueued */ |
339 | dprintk("svc: transport %p busy, not enqueued\n", xprt); | 339 | dprintk("svc: transport %p busy, not enqueued\n", xprt); |
340 | return; | 340 | goto out; |
341 | } | 341 | } |
342 | 342 | ||
343 | cpu = get_cpu(); | 343 | cpu = get_cpu(); |
@@ -377,7 +377,7 @@ redo_search: | |||
377 | atomic_long_inc(&pool->sp_stats.threads_woken); | 377 | atomic_long_inc(&pool->sp_stats.threads_woken); |
378 | wake_up_process(rqstp->rq_task); | 378 | wake_up_process(rqstp->rq_task); |
379 | put_cpu(); | 379 | put_cpu(); |
380 | return; | 380 | goto out; |
381 | } | 381 | } |
382 | rcu_read_unlock(); | 382 | rcu_read_unlock(); |
383 | 383 | ||
@@ -396,7 +396,10 @@ redo_search: | |||
396 | spin_unlock_bh(&pool->sp_lock); | 396 | spin_unlock_bh(&pool->sp_lock); |
397 | goto redo_search; | 397 | goto redo_search; |
398 | } | 398 | } |
399 | rqstp = NULL; | ||
399 | put_cpu(); | 400 | put_cpu(); |
401 | out: | ||
402 | trace_svc_xprt_do_enqueue(xprt, rqstp); | ||
400 | } | 403 | } |
401 | 404 | ||
402 | /* | 405 | /* |
@@ -420,7 +423,7 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | |||
420 | struct svc_xprt *xprt = NULL; | 423 | struct svc_xprt *xprt = NULL; |
421 | 424 | ||
422 | if (list_empty(&pool->sp_sockets)) | 425 | if (list_empty(&pool->sp_sockets)) |
423 | return NULL; | 426 | goto out; |
424 | 427 | ||
425 | spin_lock_bh(&pool->sp_lock); | 428 | spin_lock_bh(&pool->sp_lock); |
426 | if (likely(!list_empty(&pool->sp_sockets))) { | 429 | if (likely(!list_empty(&pool->sp_sockets))) { |
@@ -433,7 +436,8 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | |||
433 | xprt, atomic_read(&xprt->xpt_ref.refcount)); | 436 | xprt, atomic_read(&xprt->xpt_ref.refcount)); |
434 | } | 437 | } |
435 | spin_unlock_bh(&pool->sp_lock); | 438 | spin_unlock_bh(&pool->sp_lock); |
436 | 439 | out: | |
440 | trace_svc_xprt_dequeue(xprt); | ||
437 | return xprt; | 441 | return xprt; |
438 | } | 442 | } |
439 | 443 | ||
@@ -515,6 +519,7 @@ void svc_wake_up(struct svc_serv *serv) | |||
515 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
516 | dprintk("svc: daemon %p woken up.\n", rqstp); | 520 | dprintk("svc: daemon %p woken up.\n", rqstp); |
517 | wake_up_process(rqstp->rq_task); | 521 | wake_up_process(rqstp->rq_task); |
522 | trace_svc_wake_up(rqstp->rq_task->pid); | ||
518 | return; | 523 | return; |
519 | } | 524 | } |
520 | rcu_read_unlock(); | 525 | rcu_read_unlock(); |
@@ -522,6 +527,7 @@ void svc_wake_up(struct svc_serv *serv) | |||
522 | /* No free entries available */ | 527 | /* No free entries available */ |
523 | set_bit(SP_TASK_PENDING, &pool->sp_flags); | 528 | set_bit(SP_TASK_PENDING, &pool->sp_flags); |
524 | smp_wmb(); | 529 | smp_wmb(); |
530 | trace_svc_wake_up(0); | ||
525 | } | 531 | } |
526 | EXPORT_SYMBOL_GPL(svc_wake_up); | 532 | EXPORT_SYMBOL_GPL(svc_wake_up); |
527 | 533 | ||
@@ -740,7 +746,7 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) | |||
740 | dprintk("svc_recv: found XPT_CLOSE\n"); | 746 | dprintk("svc_recv: found XPT_CLOSE\n"); |
741 | svc_delete_xprt(xprt); | 747 | svc_delete_xprt(xprt); |
742 | /* Leave XPT_BUSY set on the dead xprt: */ | 748 | /* Leave XPT_BUSY set on the dead xprt: */ |
743 | return 0; | 749 | goto out; |
744 | } | 750 | } |
745 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { | 751 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { |
746 | struct svc_xprt *newxpt; | 752 | struct svc_xprt *newxpt; |
@@ -771,6 +777,8 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) | |||
771 | } | 777 | } |
772 | /* clear XPT_BUSY: */ | 778 | /* clear XPT_BUSY: */ |
773 | svc_xprt_received(xprt); | 779 | svc_xprt_received(xprt); |
780 | out: | ||
781 | trace_svc_handle_xprt(xprt, len); | ||
774 | return len; | 782 | return len; |
775 | } | 783 | } |
776 | 784 | ||