diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2009-03-11 14:10:21 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-03-11 14:10:21 -0400 |
commit | fe315e76fc3a3f9f7e1581dc22fec7e7719f0896 (patch) | |
tree | 15ba17ab92691d55f3e3168df8fef2fb366339c0 /net | |
parent | 01d37c428ae080563c0a3bb8bdfa88c65a6891d3 (diff) |
SUNRPC: Avoid spurious wake-up during UDP connect processing
To clear out old state, the UDP connect workers unconditionally invoke
xs_close() before proceeding with a new connect. Nowadays this causes
a spurious wake-up of the task waiting for the connect to complete.
This is a little racey, but usually harmless. The waiting task
immediately retries the connect via a call_bind/call_connect sequence,
which usually finds the transport already in the connected state
because the connect worker has finished in the background.
To avoid a spurious wake-up, factor the xs_close() logic that resets
the underlying socket into a helper, and have the UDP connect workers
call that helper instead of xs_close().
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/xprtsock.c | 44 |
1 files changed, 26 insertions, 18 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 29c71e645b27..1127eb934136 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -767,23 +767,13 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s | |||
767 | sk->sk_error_report = transport->old_error_report; | 767 | sk->sk_error_report = transport->old_error_report; |
768 | } | 768 | } |
769 | 769 | ||
770 | /** | 770 | static void xs_reset_transport(struct sock_xprt *transport) |
771 | * xs_close - close a socket | ||
772 | * @xprt: transport | ||
773 | * | ||
774 | * This is used when all requests are complete; ie, no DRC state remains | ||
775 | * on the server we want to save. | ||
776 | */ | ||
777 | static void xs_close(struct rpc_xprt *xprt) | ||
778 | { | 771 | { |
779 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | ||
780 | struct socket *sock = transport->sock; | 772 | struct socket *sock = transport->sock; |
781 | struct sock *sk = transport->inet; | 773 | struct sock *sk = transport->inet; |
782 | 774 | ||
783 | if (!sk) | 775 | if (sk == NULL) |
784 | goto clear_close_wait; | 776 | return; |
785 | |||
786 | dprintk("RPC: xs_close xprt %p\n", xprt); | ||
787 | 777 | ||
788 | write_lock_bh(&sk->sk_callback_lock); | 778 | write_lock_bh(&sk->sk_callback_lock); |
789 | transport->inet = NULL; | 779 | transport->inet = NULL; |
@@ -797,7 +787,23 @@ static void xs_close(struct rpc_xprt *xprt) | |||
797 | sk->sk_no_check = 0; | 787 | sk->sk_no_check = 0; |
798 | 788 | ||
799 | sock_release(sock); | 789 | sock_release(sock); |
800 | clear_close_wait: | 790 | } |
791 | |||
792 | /** | ||
793 | * xs_close - close a socket | ||
794 | * @xprt: transport | ||
795 | * | ||
796 | * This is used when all requests are complete; ie, no DRC state remains | ||
797 | * on the server we want to save. | ||
798 | */ | ||
799 | static void xs_close(struct rpc_xprt *xprt) | ||
800 | { | ||
801 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | ||
802 | |||
803 | dprintk("RPC: xs_close xprt %p\n", xprt); | ||
804 | |||
805 | xs_reset_transport(transport); | ||
806 | |||
801 | smp_mb__before_clear_bit(); | 807 | smp_mb__before_clear_bit(); |
802 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | 808 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); |
803 | clear_bit(XPRT_CLOSING, &xprt->state); | 809 | clear_bit(XPRT_CLOSING, &xprt->state); |
@@ -1537,9 +1543,10 @@ static void xs_udp_connect_worker4(struct work_struct *work) | |||
1537 | goto out; | 1543 | goto out; |
1538 | 1544 | ||
1539 | /* Start by resetting any existing state */ | 1545 | /* Start by resetting any existing state */ |
1540 | xs_close(xprt); | 1546 | xs_reset_transport(transport); |
1541 | 1547 | ||
1542 | if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { | 1548 | err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); |
1549 | if (err < 0) { | ||
1543 | dprintk("RPC: can't create UDP transport socket (%d).\n", -err); | 1550 | dprintk("RPC: can't create UDP transport socket (%d).\n", -err); |
1544 | goto out; | 1551 | goto out; |
1545 | } | 1552 | } |
@@ -1578,9 +1585,10 @@ static void xs_udp_connect_worker6(struct work_struct *work) | |||
1578 | goto out; | 1585 | goto out; |
1579 | 1586 | ||
1580 | /* Start by resetting any existing state */ | 1587 | /* Start by resetting any existing state */ |
1581 | xs_close(xprt); | 1588 | xs_reset_transport(transport); |
1582 | 1589 | ||
1583 | if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { | 1590 | err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock); |
1591 | if (err < 0) { | ||
1584 | dprintk("RPC: can't create UDP transport socket (%d).\n", -err); | 1592 | dprintk("RPC: can't create UDP transport socket (%d).\n", -err); |
1585 | goto out; | 1593 | goto out; |
1586 | } | 1594 | } |