diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-05-18 17:47:56 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-06-18 22:58:51 -0400 |
| commit | 47fcb03fefee2501e79176932a4184fc24d6f8ec (patch) | |
| tree | cb8eb34c5e54ce278b54cb6f9c820f564c183574 | |
| parent | ab52ae6db035fa425f90146327ab7d2c5d3e5654 (diff) | |
SUNRPC: Fix the TCP server's send buffer accounting
Currently, the sunrpc server is refusing to allow us to process new RPC
calls if the TCP send buffer is 2/3 full, even if we do actually have
enough free space to guarantee that we can send another request.
The following patch fixes svc_tcp_has_wspace() so that we only stop
processing requests if we know that the socket buffer cannot possibly fit
another reply.
It also fixes the tcp write_space() callback so that we only clear the
SOCK_NOSPACE flag when the TCP send buffer is less than 2/3 full.
This should ensure that the send window will grow as per the standard TCP
socket code.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
| -rw-r--r-- | net/sunrpc/svcsock.c | 35 |
1 files changed, 18 insertions, 17 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 004a2f9dc432..b09c80c56ee3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -380,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, | |||
| 380 | sock->sk->sk_sndbuf = snd * 2; | 380 | sock->sk->sk_sndbuf = snd * 2; |
| 381 | sock->sk->sk_rcvbuf = rcv * 2; | 381 | sock->sk->sk_rcvbuf = rcv * 2; |
| 382 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; | 382 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; |
| 383 | sock->sk->sk_write_space(sock->sk); | ||
| 383 | release_sock(sock->sk); | 384 | release_sock(sock->sk); |
| 384 | #endif | 385 | #endif |
| 385 | } | 386 | } |
| @@ -421,6 +422,15 @@ static void svc_write_space(struct sock *sk) | |||
| 421 | } | 422 | } |
| 422 | } | 423 | } |
| 423 | 424 | ||
| 425 | static void svc_tcp_write_space(struct sock *sk) | ||
| 426 | { | ||
| 427 | struct socket *sock = sk->sk_socket; | ||
| 428 | |||
| 429 | if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) | ||
| 430 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 431 | svc_write_space(sk); | ||
| 432 | } | ||
| 433 | |||
| 424 | /* | 434 | /* |
| 425 | * Copy the UDP datagram's destination address to the rqstp structure. | 435 | * Copy the UDP datagram's destination address to the rqstp structure. |
| 426 | * The 'destination' address in this case is the address to which the | 436 | * The 'destination' address in this case is the address to which the |
| @@ -1015,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | |||
| 1015 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | 1025 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) |
| 1016 | { | 1026 | { |
| 1017 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | 1027 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 1018 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | 1028 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; |
| 1019 | int required; | 1029 | int required; |
| 1020 | int wspace; | ||
| 1021 | 1030 | ||
| 1022 | /* | 1031 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) |
| 1023 | * Set the SOCK_NOSPACE flag before checking the available | 1032 | return 1; |
| 1024 | * sock space. | 1033 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; |
| 1025 | */ | 1034 | if (sk_stream_wspace(svsk->sk_sk) >= required) |
| 1035 | return 1; | ||
| 1026 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 1036 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
| 1027 | required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; | 1037 | return 0; |
| 1028 | wspace = sk_stream_wspace(svsk->sk_sk); | ||
| 1029 | |||
| 1030 | if (wspace < sk_stream_min_wspace(svsk->sk_sk)) | ||
| 1031 | return 0; | ||
| 1032 | if (required * 2 > wspace) | ||
| 1033 | return 0; | ||
| 1034 | |||
| 1035 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 1036 | return 1; | ||
| 1037 | } | 1038 | } |
| 1038 | 1039 | ||
| 1039 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, | 1040 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, |
| @@ -1089,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1089 | dprintk("setting up TCP socket for reading\n"); | 1090 | dprintk("setting up TCP socket for reading\n"); |
| 1090 | sk->sk_state_change = svc_tcp_state_change; | 1091 | sk->sk_state_change = svc_tcp_state_change; |
| 1091 | sk->sk_data_ready = svc_tcp_data_ready; | 1092 | sk->sk_data_ready = svc_tcp_data_ready; |
| 1092 | sk->sk_write_space = svc_write_space; | 1093 | sk->sk_write_space = svc_tcp_write_space; |
| 1093 | 1094 | ||
| 1094 | svsk->sk_reclen = 0; | 1095 | svsk->sk_reclen = 0; |
| 1095 | svsk->sk_tcplen = 0; | 1096 | svsk->sk_tcplen = 0; |
