aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/xprt.h2
-rw-r--r--net/sunrpc/xprt.c4
-rw-r--r--net/sunrpc/xprtsock.c61
3 files changed, 44 insertions, 23 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index b3ff9a815e6f..8a0629abb86a 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -232,7 +232,7 @@ int xprt_unregister_transport(struct xprt_class *type);
232void xprt_set_retrans_timeout_def(struct rpc_task *task); 232void xprt_set_retrans_timeout_def(struct rpc_task *task);
233void xprt_set_retrans_timeout_rtt(struct rpc_task *task); 233void xprt_set_retrans_timeout_rtt(struct rpc_task *task);
234void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); 234void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
235void xprt_wait_for_buffer_space(struct rpc_task *task); 235void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action);
236void xprt_write_space(struct rpc_xprt *xprt); 236void xprt_write_space(struct rpc_xprt *xprt);
237void xprt_update_rtt(struct rpc_task *task); 237void xprt_update_rtt(struct rpc_task *task);
238void xprt_adjust_cwnd(struct rpc_task *task, int result); 238void xprt_adjust_cwnd(struct rpc_task *task, int result);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 85199c647022..3ba64f9f84ba 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -447,13 +447,13 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
447 * @task: task to be put to sleep 447 * @task: task to be put to sleep
448 * 448 *
449 */ 449 */
450void xprt_wait_for_buffer_space(struct rpc_task *task) 450void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
451{ 451{
452 struct rpc_rqst *req = task->tk_rqstp; 452 struct rpc_rqst *req = task->tk_rqstp;
453 struct rpc_xprt *xprt = req->rq_xprt; 453 struct rpc_xprt *xprt = req->rq_xprt;
454 454
455 task->tk_timeout = req->rq_timeout; 455 task->tk_timeout = req->rq_timeout;
456 rpc_sleep_on(&xprt->pending, task, NULL); 456 rpc_sleep_on(&xprt->pending, task, action);
457} 457}
458EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); 458EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
459 459
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 8bd3b0f73ac0..4c2462e2f2b2 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -516,6 +516,14 @@ out:
516 return sent; 516 return sent;
517} 517}
518 518
519static void xs_nospace_callback(struct rpc_task *task)
520{
521 struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
522
523 transport->inet->sk_write_pending--;
524 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
525}
526
519/** 527/**
520 * xs_nospace - place task on wait queue if transmit was incomplete 528 * xs_nospace - place task on wait queue if transmit was incomplete
521 * @task: task to put to sleep 529 * @task: task to put to sleep
@@ -531,20 +539,27 @@ static void xs_nospace(struct rpc_task *task)
531 task->tk_pid, req->rq_slen - req->rq_bytes_sent, 539 task->tk_pid, req->rq_slen - req->rq_bytes_sent,
532 req->rq_slen); 540 req->rq_slen);
533 541
534 if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { 542 /* Protect against races with write_space */
535 /* Protect against races with write_space */ 543 spin_lock_bh(&xprt->transport_lock);
536 spin_lock_bh(&xprt->transport_lock); 544
537 545 /* Don't race with disconnect */
538 /* Don't race with disconnect */ 546 if (xprt_connected(xprt)) {
539 if (!xprt_connected(xprt)) 547 if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
540 task->tk_status = -ENOTCONN; 548 /*
541 else if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) 549 * Notify TCP that we're limited by the application
542 xprt_wait_for_buffer_space(task); 550 * window size
551 */
552 set_bit(SOCK_NOSPACE, &transport->sock->flags);
553 transport->inet->sk_write_pending++;
554 /* ...and wait for more buffer space */
555 xprt_wait_for_buffer_space(task, xs_nospace_callback);
556 }
557 } else {
558 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
559 task->tk_status = -ENOTCONN;
560 }
543 561
544 spin_unlock_bh(&xprt->transport_lock); 562 spin_unlock_bh(&xprt->transport_lock);
545 } else
546 /* Keep holding the socket if it is blocked */
547 rpc_delay(task, HZ>>4);
548} 563}
549 564
550/** 565/**
@@ -588,19 +603,20 @@ static int xs_udp_send_request(struct rpc_task *task)
588 } 603 }
589 604
590 switch (status) { 605 switch (status) {
606 case -EAGAIN:
607 xs_nospace(task);
608 break;
591 case -ENETUNREACH: 609 case -ENETUNREACH:
592 case -EPIPE: 610 case -EPIPE:
593 case -ECONNREFUSED: 611 case -ECONNREFUSED:
594 /* When the server has died, an ICMP port unreachable message 612 /* When the server has died, an ICMP port unreachable message
595 * prompts ECONNREFUSED. */ 613 * prompts ECONNREFUSED. */
596 break; 614 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
597 case -EAGAIN:
598 xs_nospace(task);
599 break; 615 break;
600 default: 616 default:
617 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
601 dprintk("RPC: sendmsg returned unrecognized error %d\n", 618 dprintk("RPC: sendmsg returned unrecognized error %d\n",
602 -status); 619 -status);
603 break;
604 } 620 }
605 621
606 return status; 622 return status;
@@ -695,12 +711,13 @@ static int xs_tcp_send_request(struct rpc_task *task)
695 case -ENOTCONN: 711 case -ENOTCONN:
696 case -EPIPE: 712 case -EPIPE:
697 status = -ENOTCONN; 713 status = -ENOTCONN;
714 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
698 break; 715 break;
699 default: 716 default:
700 dprintk("RPC: sendmsg returned unrecognized error %d\n", 717 dprintk("RPC: sendmsg returned unrecognized error %d\n",
701 -status); 718 -status);
719 clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
702 xs_tcp_shutdown(xprt); 720 xs_tcp_shutdown(xprt);
703 break;
704 } 721 }
705 722
706 return status; 723 return status;
@@ -1189,9 +1206,11 @@ static void xs_udp_write_space(struct sock *sk)
1189 1206
1190 if (unlikely(!(sock = sk->sk_socket))) 1207 if (unlikely(!(sock = sk->sk_socket)))
1191 goto out; 1208 goto out;
1209 clear_bit(SOCK_NOSPACE, &sock->flags);
1210
1192 if (unlikely(!(xprt = xprt_from_sock(sk)))) 1211 if (unlikely(!(xprt = xprt_from_sock(sk))))
1193 goto out; 1212 goto out;
1194 if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) 1213 if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
1195 goto out; 1214 goto out;
1196 1215
1197 xprt_write_space(xprt); 1216 xprt_write_space(xprt);
@@ -1222,9 +1241,11 @@ static void xs_tcp_write_space(struct sock *sk)
1222 1241
1223 if (unlikely(!(sock = sk->sk_socket))) 1242 if (unlikely(!(sock = sk->sk_socket)))
1224 goto out; 1243 goto out;
1244 clear_bit(SOCK_NOSPACE, &sock->flags);
1245
1225 if (unlikely(!(xprt = xprt_from_sock(sk)))) 1246 if (unlikely(!(xprt = xprt_from_sock(sk))))
1226 goto out; 1247 goto out;
1227 if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) 1248 if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
1228 goto out; 1249 goto out;
1229 1250
1230 xprt_write_space(xprt); 1251 xprt_write_space(xprt);