diff options
author | Chuck Lever <cel@citi.umich.edu> | 2005-08-11 16:25:50 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-09-23 12:38:28 -0400 |
commit | c7b2cae8a634015b72941ba2fc6c4bc9b8d3a129 (patch) | |
tree | 95f561877d67eed80a823daa6ef0c00ad1c060eb /net/sunrpc | |
parent | 55aa4f58aa43dc9a51fb80010630d94b96053a2e (diff) |
[PATCH] RPC: separate TCP and UDP write space callbacks
Split the socket write space callback function into a TCP version and UDP
version, eliminating one dependence on the "xprt->stream" variable.
Keep the common pieces of this path in xprt.c so other transports can use
it too.
Test-plan:
Write-intensive workload on a single mount point.
Version: Thu, 11 Aug 2005 16:07:51 -0400
Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/xprt.c | 34 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 84 |
2 files changed, 87 insertions, 31 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 247fa1ec870c..31ef7dc7eed6 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -241,6 +241,40 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status) | |||
241 | rpc_wake_up(&xprt->pending); | 241 | rpc_wake_up(&xprt->pending); |
242 | } | 242 | } |
243 | 243 | ||
244 | /** | ||
245 | * xprt_wait_for_buffer_space - wait for transport output buffer to clear | ||
246 | * @task: task to be put to sleep | ||
247 | * | ||
248 | */ | ||
249 | void xprt_wait_for_buffer_space(struct rpc_task *task) | ||
250 | { | ||
251 | struct rpc_rqst *req = task->tk_rqstp; | ||
252 | struct rpc_xprt *xprt = req->rq_xprt; | ||
253 | |||
254 | task->tk_timeout = req->rq_timeout; | ||
255 | rpc_sleep_on(&xprt->pending, task, NULL, NULL); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * xprt_write_space - wake the task waiting for transport output buffer space | ||
260 | * @xprt: transport with waiting tasks | ||
261 | * | ||
262 | * Can be called in a soft IRQ context, so xprt_write_space never sleeps. | ||
263 | */ | ||
264 | void xprt_write_space(struct rpc_xprt *xprt) | ||
265 | { | ||
266 | if (unlikely(xprt->shutdown)) | ||
267 | return; | ||
268 | |||
269 | spin_lock_bh(&xprt->transport_lock); | ||
270 | if (xprt->snd_task) { | ||
271 | dprintk("RPC: write space: waking waiting task on xprt %p\n", | ||
272 | xprt); | ||
273 | rpc_wake_up_task(xprt->snd_task); | ||
274 | } | ||
275 | spin_unlock_bh(&xprt->transport_lock); | ||
276 | } | ||
277 | |||
244 | static void xprt_reset_majortimeo(struct rpc_rqst *req) | 278 | static void xprt_reset_majortimeo(struct rpc_rqst *req) |
245 | { | 279 | { |
246 | struct rpc_timeout *to = &req->rq_xprt->timeout; | 280 | struct rpc_timeout *to = &req->rq_xprt->timeout; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7f0b9f7f167b..70a772d7a796 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -308,15 +308,13 @@ static int xs_send_request(struct rpc_task *task) | |||
308 | 308 | ||
309 | if (status == -EAGAIN) { | 309 | if (status == -EAGAIN) { |
310 | if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { | 310 | if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { |
311 | /* Protect against races with xs_write_space */ | 311 | /* Protect against races with write_space */ |
312 | spin_lock_bh(&xprt->transport_lock); | 312 | spin_lock_bh(&xprt->transport_lock); |
313 | /* Don't race with disconnect */ | 313 | /* Don't race with disconnect */ |
314 | if (!xprt_connected(xprt)) | 314 | if (!xprt_connected(xprt)) |
315 | task->tk_status = -ENOTCONN; | 315 | task->tk_status = -ENOTCONN; |
316 | else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { | 316 | else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) |
317 | task->tk_timeout = req->rq_timeout; | 317 | xprt_wait_for_buffer_space(task); |
318 | rpc_sleep_on(&xprt->pending, task, NULL, NULL); | ||
319 | } | ||
320 | spin_unlock_bh(&xprt->transport_lock); | 318 | spin_unlock_bh(&xprt->transport_lock); |
321 | return status; | 319 | return status; |
322 | } | 320 | } |
@@ -721,45 +719,68 @@ static void xs_tcp_state_change(struct sock *sk) | |||
721 | } | 719 | } |
722 | 720 | ||
723 | /** | 721 | /** |
724 | * xs_write_space - callback invoked when socket buffer space becomes | 722 | * xs_udp_write_space - callback invoked when socket buffer space |
725 | * available | 723 | * becomes available |
726 | * @sk: socket whose state has changed | 724 | * @sk: socket whose state has changed |
727 | * | 725 | * |
728 | * Called when more output buffer space is available for this socket. | 726 | * Called when more output buffer space is available for this socket. |
729 | * We try not to wake our writers until they can make "significant" | 727 | * We try not to wake our writers until they can make "significant" |
730 | * progress, otherwise we'll waste resources thrashing sock_sendmsg | 728 | * progress, otherwise we'll waste resources thrashing kernel_sendmsg |
731 | * with a bunch of small requests. | 729 | * with a bunch of small requests. |
732 | */ | 730 | */ |
733 | static void xs_write_space(struct sock *sk) | 731 | static void xs_udp_write_space(struct sock *sk) |
734 | { | 732 | { |
735 | struct rpc_xprt *xprt; | ||
736 | struct socket *sock; | ||
737 | |||
738 | read_lock(&sk->sk_callback_lock); | 733 | read_lock(&sk->sk_callback_lock); |
739 | if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) | ||
740 | goto out; | ||
741 | if (xprt->shutdown) | ||
742 | goto out; | ||
743 | 734 | ||
744 | /* Wait until we have enough socket memory */ | 735 | /* from net/core/sock.c:sock_def_write_space */ |
745 | if (xprt->stream) { | 736 | if (sock_writeable(sk)) { |
746 | /* from net/core/stream.c:sk_stream_write_space */ | 737 | struct socket *sock; |
747 | if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk)) | 738 | struct rpc_xprt *xprt; |
739 | |||
740 | if (unlikely(!(sock = sk->sk_socket))) | ||
748 | goto out; | 741 | goto out; |
749 | } else { | 742 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
750 | /* from net/core/sock.c:sock_def_write_space */ | 743 | goto out; |
751 | if (!sock_writeable(sk)) | 744 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) |
752 | goto out; | 745 | goto out; |
746 | |||
747 | xprt_write_space(xprt); | ||
753 | } | 748 | } |
754 | 749 | ||
755 | if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) | 750 | out: |
756 | goto out; | 751 | read_unlock(&sk->sk_callback_lock); |
752 | } | ||
757 | 753 | ||
758 | spin_lock_bh(&xprt->transport_lock); | 754 | /** |
759 | if (xprt->snd_task) | 755 | * xs_tcp_write_space - callback invoked when socket buffer space |
760 | rpc_wake_up_task(xprt->snd_task); | 756 | * becomes available |
761 | spin_unlock_bh(&xprt->transport_lock); | 757 | * @sk: socket whose state has changed |
762 | out: | 758 | * |
759 | * Called when more output buffer space is available for this socket. | ||
760 | * We try not to wake our writers until they can make "significant" | ||
761 | * progress, otherwise we'll waste resources thrashing kernel_sendmsg | ||
762 | * with a bunch of small requests. | ||
763 | */ | ||
764 | static void xs_tcp_write_space(struct sock *sk) | ||
765 | { | ||
766 | read_lock(&sk->sk_callback_lock); | ||
767 | |||
768 | /* from net/core/stream.c:sk_stream_write_space */ | ||
769 | if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { | ||
770 | struct socket *sock; | ||
771 | struct rpc_xprt *xprt; | ||
772 | |||
773 | if (unlikely(!(sock = sk->sk_socket))) | ||
774 | goto out; | ||
775 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | ||
776 | goto out; | ||
777 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | ||
778 | goto out; | ||
779 | |||
780 | xprt_write_space(xprt); | ||
781 | } | ||
782 | |||
783 | out: | ||
763 | read_unlock(&sk->sk_callback_lock); | 784 | read_unlock(&sk->sk_callback_lock); |
764 | } | 785 | } |
765 | 786 | ||
@@ -855,15 +876,16 @@ static void xs_bind(struct rpc_xprt *xprt, struct socket *sock) | |||
855 | xprt->old_write_space = sk->sk_write_space; | 876 | xprt->old_write_space = sk->sk_write_space; |
856 | if (xprt->prot == IPPROTO_UDP) { | 877 | if (xprt->prot == IPPROTO_UDP) { |
857 | sk->sk_data_ready = xs_udp_data_ready; | 878 | sk->sk_data_ready = xs_udp_data_ready; |
879 | sk->sk_write_space = xs_udp_write_space; | ||
858 | sk->sk_no_check = UDP_CSUM_NORCV; | 880 | sk->sk_no_check = UDP_CSUM_NORCV; |
859 | xprt_set_connected(xprt); | 881 | xprt_set_connected(xprt); |
860 | } else { | 882 | } else { |
861 | tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ | 883 | tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ |
862 | sk->sk_data_ready = xs_tcp_data_ready; | 884 | sk->sk_data_ready = xs_tcp_data_ready; |
863 | sk->sk_state_change = xs_tcp_state_change; | 885 | sk->sk_state_change = xs_tcp_state_change; |
886 | sk->sk_write_space = xs_tcp_write_space; | ||
864 | xprt_clear_connected(xprt); | 887 | xprt_clear_connected(xprt); |
865 | } | 888 | } |
866 | sk->sk_write_space = xs_write_space; | ||
867 | 889 | ||
868 | /* Reset to new socket */ | 890 | /* Reset to new socket */ |
869 | xprt->sock = sock; | 891 | xprt->sock = sock; |