diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-03-11 14:37:59 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-03-11 14:37:59 -0400 |
commit | c8485e4d634f6df155040293928707f127f0d06d (patch) | |
tree | 72ec8a7ea829e4f7df4648e646353c55a037e50e | |
parent | 40d2549db5f515e415894def98b49db7d4c56714 (diff) |
SUNRPC: Handle ECONNREFUSED correctly in xprt_transmit()
If we get an ECONNREFUSED error, we currently go to sleep on the
'xprt->sending' wait queue. The problem is that no timeout is set there,
and there is nothing else that will wake the task up later.
We should deal with ECONNREFUSED in call_status, given that is where we
also deal with -EHOSTDOWN, and friends.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | net/sunrpc/clnt.c | 7 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 38 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 26 |
3 files changed, 34 insertions, 37 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 07e9b05321e6..145715b53115 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1117,10 +1117,12 @@ call_transmit_status(struct rpc_task *task) | |||
1117 | * then hold onto the transport lock. | 1117 | * then hold onto the transport lock. |
1118 | */ | 1118 | */ |
1119 | case -ECONNREFUSED: | 1119 | case -ECONNREFUSED: |
1120 | case -ECONNRESET: | ||
1120 | case -ENOTCONN: | 1121 | case -ENOTCONN: |
1121 | case -EHOSTDOWN: | 1122 | case -EHOSTDOWN: |
1122 | case -EHOSTUNREACH: | 1123 | case -EHOSTUNREACH: |
1123 | case -ENETUNREACH: | 1124 | case -ENETUNREACH: |
1125 | case -EPIPE: | ||
1124 | rpc_task_force_reencode(task); | 1126 | rpc_task_force_reencode(task); |
1125 | } | 1127 | } |
1126 | } | 1128 | } |
@@ -1162,9 +1164,12 @@ call_status(struct rpc_task *task) | |||
1162 | xprt_conditional_disconnect(task->tk_xprt, | 1164 | xprt_conditional_disconnect(task->tk_xprt, |
1163 | req->rq_connect_cookie); | 1165 | req->rq_connect_cookie); |
1164 | break; | 1166 | break; |
1167 | case -ECONNRESET: | ||
1165 | case -ECONNREFUSED: | 1168 | case -ECONNREFUSED: |
1166 | case -ENOTCONN: | ||
1167 | rpc_force_rebind(clnt); | 1169 | rpc_force_rebind(clnt); |
1170 | rpc_delay(task, 3*HZ); | ||
1171 | case -EPIPE: | ||
1172 | case -ENOTCONN: | ||
1168 | task->tk_action = call_bind; | 1173 | task->tk_action = call_bind; |
1169 | break; | 1174 | break; |
1170 | case -EAGAIN: | 1175 | case -EAGAIN: |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d1afec640394..d588e755e107 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -901,32 +901,26 @@ void xprt_transmit(struct rpc_task *task) | |||
901 | req->rq_connect_cookie = xprt->connect_cookie; | 901 | req->rq_connect_cookie = xprt->connect_cookie; |
902 | req->rq_xtime = jiffies; | 902 | req->rq_xtime = jiffies; |
903 | status = xprt->ops->send_request(task); | 903 | status = xprt->ops->send_request(task); |
904 | if (status == 0) { | 904 | if (status != 0) { |
905 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); | 905 | task->tk_status = status; |
906 | spin_lock_bh(&xprt->transport_lock); | 906 | return; |
907 | } | ||
907 | 908 | ||
908 | xprt->ops->set_retrans_timeout(task); | 909 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); |
910 | spin_lock_bh(&xprt->transport_lock); | ||
909 | 911 | ||
910 | xprt->stat.sends++; | 912 | xprt->ops->set_retrans_timeout(task); |
911 | xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; | ||
912 | xprt->stat.bklog_u += xprt->backlog.qlen; | ||
913 | 913 | ||
914 | /* Don't race with disconnect */ | 914 | xprt->stat.sends++; |
915 | if (!xprt_connected(xprt)) | 915 | xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; |
916 | task->tk_status = -ENOTCONN; | 916 | xprt->stat.bklog_u += xprt->backlog.qlen; |
917 | else if (!req->rq_received) | ||
918 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | ||
919 | spin_unlock_bh(&xprt->transport_lock); | ||
920 | return; | ||
921 | } | ||
922 | 917 | ||
923 | /* Note: at this point, task->tk_sleeping has not yet been set, | 918 | /* Don't race with disconnect */ |
924 | * hence there is no danger of the waking up task being put on | 919 | if (!xprt_connected(xprt)) |
925 | * schedq, and being picked up by a parallel run of rpciod(). | 920 | task->tk_status = -ENOTCONN; |
926 | */ | 921 | else if (!req->rq_received) |
927 | task->tk_status = status; | 922 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
928 | if (status == -ECONNREFUSED) | 923 | spin_unlock_bh(&xprt->transport_lock); |
929 | rpc_sleep_on(&xprt->sending, task, NULL); | ||
930 | } | 924 | } |
931 | 925 | ||
932 | static inline void do_xprt_reserve(struct rpc_task *task) | 926 | static inline void do_xprt_reserve(struct rpc_task *task) |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9d1898f6ee87..5e8198bede81 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -594,6 +594,8 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
594 | /* Still some bytes left; set up for a retry later. */ | 594 | /* Still some bytes left; set up for a retry later. */ |
595 | status = -EAGAIN; | 595 | status = -EAGAIN; |
596 | } | 596 | } |
597 | if (!transport->sock) | ||
598 | goto out; | ||
597 | 599 | ||
598 | switch (status) { | 600 | switch (status) { |
599 | case -ENOTSOCK: | 601 | case -ENOTSOCK: |
@@ -603,19 +605,17 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
603 | case -EAGAIN: | 605 | case -EAGAIN: |
604 | xs_nospace(task); | 606 | xs_nospace(task); |
605 | break; | 607 | break; |
608 | default: | ||
609 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | ||
610 | -status); | ||
606 | case -ENETUNREACH: | 611 | case -ENETUNREACH: |
607 | case -EPIPE: | 612 | case -EPIPE: |
608 | case -ECONNREFUSED: | 613 | case -ECONNREFUSED: |
609 | /* When the server has died, an ICMP port unreachable message | 614 | /* When the server has died, an ICMP port unreachable message |
610 | * prompts ECONNREFUSED. */ | 615 | * prompts ECONNREFUSED. */ |
611 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | 616 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
612 | break; | ||
613 | default: | ||
614 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
615 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | ||
616 | -status); | ||
617 | } | 617 | } |
618 | 618 | out: | |
619 | return status; | 619 | return status; |
620 | } | 620 | } |
621 | 621 | ||
@@ -697,6 +697,8 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
697 | status = -EAGAIN; | 697 | status = -EAGAIN; |
698 | break; | 698 | break; |
699 | } | 699 | } |
700 | if (!transport->sock) | ||
701 | goto out; | ||
700 | 702 | ||
701 | switch (status) { | 703 | switch (status) { |
702 | case -ENOTSOCK: | 704 | case -ENOTSOCK: |
@@ -706,21 +708,17 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
706 | case -EAGAIN: | 708 | case -EAGAIN: |
707 | xs_nospace(task); | 709 | xs_nospace(task); |
708 | break; | 710 | break; |
711 | default: | ||
712 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | ||
713 | -status); | ||
709 | case -ECONNRESET: | 714 | case -ECONNRESET: |
710 | xs_tcp_shutdown(xprt); | 715 | xs_tcp_shutdown(xprt); |
711 | case -ECONNREFUSED: | 716 | case -ECONNREFUSED: |
712 | case -ENOTCONN: | 717 | case -ENOTCONN: |
713 | case -EPIPE: | 718 | case -EPIPE: |
714 | status = -ENOTCONN; | ||
715 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
716 | break; | ||
717 | default: | ||
718 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | ||
719 | -status); | ||
720 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | 719 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
721 | xs_tcp_shutdown(xprt); | ||
722 | } | 720 | } |
723 | 721 | out: | |
724 | return status; | 722 | return status; |
725 | } | 723 | } |
726 | 724 | ||