diff options
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r-- | net/sunrpc/xprt.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 06ca058572f2..f412a852bc73 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -12,8 +12,9 @@ | |||
12 | * - Next, the caller puts together the RPC message, stuffs it into | 12 | * - Next, the caller puts together the RPC message, stuffs it into |
13 | * the request struct, and calls xprt_transmit(). | 13 | * the request struct, and calls xprt_transmit(). |
14 | * - xprt_transmit sends the message and installs the caller on the | 14 | * - xprt_transmit sends the message and installs the caller on the |
15 | * transport's wait list. At the same time, it installs a timer that | 15 | * transport's wait list. At the same time, if a reply is expected, |
16 | * is run after the packet's timeout has expired. | 16 | * it installs a timer that is run after the packet's timeout has |
17 | * expired. | ||
17 | * - When a packet arrives, the data_ready handler walks the list of | 18 | * - When a packet arrives, the data_ready handler walks the list of |
18 | * pending requests for that transport. If a matching XID is found, the | 19 | * pending requests for that transport. If a matching XID is found, the |
19 | * caller is woken up, and the timer removed. | 20 | * caller is woken up, and the timer removed. |
@@ -46,6 +47,8 @@ | |||
46 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
47 | #include <linux/sunrpc/metrics.h> | 48 | #include <linux/sunrpc/metrics.h> |
48 | 49 | ||
50 | #include "sunrpc.h" | ||
51 | |||
49 | /* | 52 | /* |
50 | * Local variables | 53 | * Local variables |
51 | */ | 54 | */ |
@@ -192,8 +195,8 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); | |||
192 | */ | 195 | */ |
193 | int xprt_reserve_xprt(struct rpc_task *task) | 196 | int xprt_reserve_xprt(struct rpc_task *task) |
194 | { | 197 | { |
195 | struct rpc_xprt *xprt = task->tk_xprt; | ||
196 | struct rpc_rqst *req = task->tk_rqstp; | 198 | struct rpc_rqst *req = task->tk_rqstp; |
199 | struct rpc_xprt *xprt = req->rq_xprt; | ||
197 | 200 | ||
198 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 201 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
199 | if (task == xprt->snd_task) | 202 | if (task == xprt->snd_task) |
@@ -803,9 +806,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) | |||
803 | 806 | ||
804 | list_del_init(&req->rq_list); | 807 | list_del_init(&req->rq_list); |
805 | req->rq_private_buf.len = copied; | 808 | req->rq_private_buf.len = copied; |
806 | /* Ensure all writes are done before we update req->rq_received */ | 809 | /* Ensure all writes are done before we update */ |
810 | /* req->rq_reply_bytes_recvd */ | ||
807 | smp_wmb(); | 811 | smp_wmb(); |
808 | req->rq_received = copied; | 812 | req->rq_reply_bytes_recvd = copied; |
809 | rpc_wake_up_queued_task(&xprt->pending, task); | 813 | rpc_wake_up_queued_task(&xprt->pending, task); |
810 | } | 814 | } |
811 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); | 815 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); |
@@ -820,7 +824,7 @@ static void xprt_timer(struct rpc_task *task) | |||
820 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); | 824 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); |
821 | 825 | ||
822 | spin_lock_bh(&xprt->transport_lock); | 826 | spin_lock_bh(&xprt->transport_lock); |
823 | if (!req->rq_received) { | 827 | if (!req->rq_reply_bytes_recvd) { |
824 | if (xprt->ops->timer) | 828 | if (xprt->ops->timer) |
825 | xprt->ops->timer(task); | 829 | xprt->ops->timer(task); |
826 | } else | 830 | } else |
@@ -842,8 +846,8 @@ int xprt_prepare_transmit(struct rpc_task *task) | |||
842 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); | 846 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); |
843 | 847 | ||
844 | spin_lock_bh(&xprt->transport_lock); | 848 | spin_lock_bh(&xprt->transport_lock); |
845 | if (req->rq_received && !req->rq_bytes_sent) { | 849 | if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) { |
846 | err = req->rq_received; | 850 | err = req->rq_reply_bytes_recvd; |
847 | goto out_unlock; | 851 | goto out_unlock; |
848 | } | 852 | } |
849 | if (!xprt->ops->reserve_xprt(task)) | 853 | if (!xprt->ops->reserve_xprt(task)) |
@@ -855,7 +859,7 @@ out_unlock: | |||
855 | 859 | ||
856 | void xprt_end_transmit(struct rpc_task *task) | 860 | void xprt_end_transmit(struct rpc_task *task) |
857 | { | 861 | { |
858 | xprt_release_write(task->tk_xprt, task); | 862 | xprt_release_write(task->tk_rqstp->rq_xprt, task); |
859 | } | 863 | } |
860 | 864 | ||
861 | /** | 865 | /** |
@@ -872,8 +876,11 @@ void xprt_transmit(struct rpc_task *task) | |||
872 | 876 | ||
873 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 877 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
874 | 878 | ||
875 | if (!req->rq_received) { | 879 | if (!req->rq_reply_bytes_recvd) { |
876 | if (list_empty(&req->rq_list)) { | 880 | if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { |
881 | /* | ||
882 | * Add to the list only if we're expecting a reply | ||
883 | */ | ||
877 | spin_lock_bh(&xprt->transport_lock); | 884 | spin_lock_bh(&xprt->transport_lock); |
878 | /* Update the softirq receive buffer */ | 885 | /* Update the softirq receive buffer */ |
879 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | 886 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, |
@@ -908,8 +915,13 @@ void xprt_transmit(struct rpc_task *task) | |||
908 | /* Don't race with disconnect */ | 915 | /* Don't race with disconnect */ |
909 | if (!xprt_connected(xprt)) | 916 | if (!xprt_connected(xprt)) |
910 | task->tk_status = -ENOTCONN; | 917 | task->tk_status = -ENOTCONN; |
911 | else if (!req->rq_received) | 918 | else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) { |
919 | /* | ||
920 | * Sleep on the pending queue since | ||
921 | * we're expecting a reply. | ||
922 | */ | ||
912 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | 923 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
924 | } | ||
913 | spin_unlock_bh(&xprt->transport_lock); | 925 | spin_unlock_bh(&xprt->transport_lock); |
914 | } | 926 | } |
915 | 927 | ||
@@ -982,11 +994,17 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
982 | */ | 994 | */ |
983 | void xprt_release(struct rpc_task *task) | 995 | void xprt_release(struct rpc_task *task) |
984 | { | 996 | { |
985 | struct rpc_xprt *xprt = task->tk_xprt; | 997 | struct rpc_xprt *xprt; |
986 | struct rpc_rqst *req; | 998 | struct rpc_rqst *req; |
999 | int is_bc_request; | ||
987 | 1000 | ||
988 | if (!(req = task->tk_rqstp)) | 1001 | if (!(req = task->tk_rqstp)) |
989 | return; | 1002 | return; |
1003 | |||
1004 | /* Preallocated backchannel request? */ | ||
1005 | is_bc_request = bc_prealloc(req); | ||
1006 | |||
1007 | xprt = req->rq_xprt; | ||
990 | rpc_count_iostats(task); | 1008 | rpc_count_iostats(task); |
991 | spin_lock_bh(&xprt->transport_lock); | 1009 | spin_lock_bh(&xprt->transport_lock); |
992 | xprt->ops->release_xprt(xprt, task); | 1010 | xprt->ops->release_xprt(xprt, task); |
@@ -999,10 +1017,19 @@ void xprt_release(struct rpc_task *task) | |||
999 | mod_timer(&xprt->timer, | 1017 | mod_timer(&xprt->timer, |
1000 | xprt->last_used + xprt->idle_timeout); | 1018 | xprt->last_used + xprt->idle_timeout); |
1001 | spin_unlock_bh(&xprt->transport_lock); | 1019 | spin_unlock_bh(&xprt->transport_lock); |
1002 | xprt->ops->buf_free(req->rq_buffer); | 1020 | if (!bc_prealloc(req)) |
1021 | xprt->ops->buf_free(req->rq_buffer); | ||
1003 | task->tk_rqstp = NULL; | 1022 | task->tk_rqstp = NULL; |
1004 | if (req->rq_release_snd_buf) | 1023 | if (req->rq_release_snd_buf) |
1005 | req->rq_release_snd_buf(req); | 1024 | req->rq_release_snd_buf(req); |
1025 | |||
1026 | /* | ||
1027 | * Early exit if this is a backchannel preallocated request. | ||
1028 | * There is no need to have it added to the RPC slot list. | ||
1029 | */ | ||
1030 | if (is_bc_request) | ||
1031 | return; | ||
1032 | |||
1006 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1033 | memset(req, 0, sizeof(*req)); /* mark unused */ |
1007 | 1034 | ||
1008 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); | 1035 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); |
@@ -1049,6 +1076,11 @@ found: | |||
1049 | 1076 | ||
1050 | INIT_LIST_HEAD(&xprt->free); | 1077 | INIT_LIST_HEAD(&xprt->free); |
1051 | INIT_LIST_HEAD(&xprt->recv); | 1078 | INIT_LIST_HEAD(&xprt->recv); |
1079 | #if defined(CONFIG_NFS_V4_1) | ||
1080 | spin_lock_init(&xprt->bc_pa_lock); | ||
1081 | INIT_LIST_HEAD(&xprt->bc_pa_list); | ||
1082 | #endif /* CONFIG_NFS_V4_1 */ | ||
1083 | |||
1052 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); | 1084 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); |
1053 | setup_timer(&xprt->timer, xprt_init_autodisconnect, | 1085 | setup_timer(&xprt->timer, xprt_init_autodisconnect, |
1054 | (unsigned long)xprt); | 1086 | (unsigned long)xprt); |