diff options
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 64 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
3 files changed, 57 insertions, 12 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index ac08e99a81cb..eee1c6877851 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -132,6 +132,7 @@ struct rpc_xprt; | |||
| 132 | 132 | ||
| 133 | struct rpc_xprt_ops { | 133 | struct rpc_xprt_ops { |
| 134 | void (*set_buffer_size)(struct rpc_xprt *xprt); | 134 | void (*set_buffer_size)(struct rpc_xprt *xprt); |
| 135 | int (*reserve_xprt)(struct rpc_task *task); | ||
| 135 | void (*connect)(struct rpc_task *task); | 136 | void (*connect)(struct rpc_task *task); |
| 136 | int (*send_request)(struct rpc_task *task); | 137 | int (*send_request)(struct rpc_task *task); |
| 137 | void (*set_retrans_timeout)(struct rpc_task *task); | 138 | void (*set_retrans_timeout)(struct rpc_task *task); |
| @@ -232,6 +233,8 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long | |||
| 232 | */ | 233 | */ |
| 233 | void xprt_connect(struct rpc_task *task); | 234 | void xprt_connect(struct rpc_task *task); |
| 234 | void xprt_reserve(struct rpc_task *task); | 235 | void xprt_reserve(struct rpc_task *task); |
| 236 | int xprt_reserve_xprt(struct rpc_task *task); | ||
| 237 | int xprt_reserve_xprt_cong(struct rpc_task *task); | ||
| 235 | int xprt_prepare_transmit(struct rpc_task *task); | 238 | int xprt_prepare_transmit(struct rpc_task *task); |
| 236 | void xprt_transmit(struct rpc_task *task); | 239 | void xprt_transmit(struct rpc_task *task); |
| 237 | int xprt_adjust_timeout(struct rpc_rqst *req); | 240 | int xprt_adjust_timeout(struct rpc_rqst *req); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1ac2fbe05102..2d1e8b83dd68 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -64,14 +64,56 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); | |||
| 64 | 64 | ||
| 65 | static int xprt_clear_backlog(struct rpc_xprt *xprt); | 65 | static int xprt_clear_backlog(struct rpc_xprt *xprt); |
| 66 | 66 | ||
| 67 | /** | ||
| 68 | * xprt_reserve_xprt - serialize write access to transports | ||
| 69 | * @task: task that is requesting access to the transport | ||
| 70 | * | ||
| 71 | * This prevents mixing the payload of separate requests, and prevents | ||
| 72 | * transport connects from colliding with writes. No congestion control | ||
| 73 | * is provided. | ||
| 74 | */ | ||
| 75 | int xprt_reserve_xprt(struct rpc_task *task) | ||
| 76 | { | ||
| 77 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 78 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 79 | |||
| 80 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | ||
| 81 | if (task == xprt->snd_task) | ||
| 82 | return 1; | ||
| 83 | if (task == NULL) | ||
| 84 | return 0; | ||
| 85 | goto out_sleep; | ||
| 86 | } | ||
| 87 | xprt->snd_task = task; | ||
| 88 | if (req) { | ||
| 89 | req->rq_bytes_sent = 0; | ||
| 90 | req->rq_ntrans++; | ||
| 91 | } | ||
| 92 | return 1; | ||
| 93 | |||
| 94 | out_sleep: | ||
| 95 | dprintk("RPC: %4d failed to lock transport %p\n", | ||
| 96 | task->tk_pid, xprt); | ||
| 97 | task->tk_timeout = 0; | ||
| 98 | task->tk_status = -EAGAIN; | ||
| 99 | if (req && req->rq_ntrans) | ||
| 100 | rpc_sleep_on(&xprt->resend, task, NULL, NULL); | ||
| 101 | else | ||
| 102 | rpc_sleep_on(&xprt->sending, task, NULL, NULL); | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 67 | /* | 106 | /* |
| 68 | * Serialize write access to transports, in order to prevent different | 107 | * xprt_reserve_xprt_cong - serialize write access to transports |
| 69 | * requests from interfering with each other. | 108 | * @task: task that is requesting access to the transport |
| 70 | * Also prevents transport connects from colliding with writes. | 109 | * |
| 110 | * Same as xprt_reserve_xprt, but Van Jacobson congestion control is | ||
| 111 | * integrated into the decision of whether a request is allowed to be | ||
| 112 | * woken up and given access to the transport. | ||
| 71 | */ | 113 | */ |
| 72 | static int | 114 | int xprt_reserve_xprt_cong(struct rpc_task *task) |
| 73 | __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | ||
| 74 | { | 115 | { |
| 116 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 75 | struct rpc_rqst *req = task->tk_rqstp; | 117 | struct rpc_rqst *req = task->tk_rqstp; |
| 76 | 118 | ||
| 77 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 119 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
| @@ -79,7 +121,7 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | |||
| 79 | return 1; | 121 | return 1; |
| 80 | goto out_sleep; | 122 | goto out_sleep; |
| 81 | } | 123 | } |
| 82 | if (xprt->nocong || __xprt_get_cong(xprt, task)) { | 124 | if (__xprt_get_cong(xprt, task)) { |
| 83 | xprt->snd_task = task; | 125 | xprt->snd_task = task; |
| 84 | if (req) { | 126 | if (req) { |
| 85 | req->rq_bytes_sent = 0; | 127 | req->rq_bytes_sent = 0; |
| @@ -101,20 +143,18 @@ out_sleep: | |||
| 101 | return 0; | 143 | return 0; |
| 102 | } | 144 | } |
| 103 | 145 | ||
| 104 | static inline int | 146 | static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) |
| 105 | xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | ||
| 106 | { | 147 | { |
| 107 | int retval; | 148 | int retval; |
| 108 | 149 | ||
| 109 | spin_lock_bh(&xprt->transport_lock); | 150 | spin_lock_bh(&xprt->transport_lock); |
| 110 | retval = __xprt_lock_write(xprt, task); | 151 | retval = xprt->ops->reserve_xprt(task); |
| 111 | spin_unlock_bh(&xprt->transport_lock); | 152 | spin_unlock_bh(&xprt->transport_lock); |
| 112 | return retval; | 153 | return retval; |
| 113 | } | 154 | } |
| 114 | 155 | ||
| 115 | 156 | ||
| 116 | static void | 157 | static void __xprt_lock_write_next(struct rpc_xprt *xprt) |
| 117 | __xprt_lock_write_next(struct rpc_xprt *xprt) | ||
| 118 | { | 158 | { |
| 119 | struct rpc_task *task; | 159 | struct rpc_task *task; |
| 120 | 160 | ||
| @@ -598,7 +638,7 @@ int xprt_prepare_transmit(struct rpc_task *task) | |||
| 598 | err = req->rq_received; | 638 | err = req->rq_received; |
| 599 | goto out_unlock; | 639 | goto out_unlock; |
| 600 | } | 640 | } |
| 601 | if (!__xprt_lock_write(xprt, task)) { | 641 | if (!xprt->ops->reserve_xprt(task)) { |
| 602 | err = -EAGAIN; | 642 | err = -EAGAIN; |
| 603 | goto out_unlock; | 643 | goto out_unlock; |
| 604 | } | 644 | } |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 79433ffd1df0..fc4fbe8ea346 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -1045,6 +1045,7 @@ static void xs_connect(struct rpc_task *task) | |||
| 1045 | 1045 | ||
| 1046 | static struct rpc_xprt_ops xs_udp_ops = { | 1046 | static struct rpc_xprt_ops xs_udp_ops = { |
| 1047 | .set_buffer_size = xs_udp_set_buffer_size, | 1047 | .set_buffer_size = xs_udp_set_buffer_size, |
| 1048 | .reserve_xprt = xprt_reserve_xprt_cong, | ||
| 1048 | .connect = xs_connect, | 1049 | .connect = xs_connect, |
| 1049 | .send_request = xs_udp_send_request, | 1050 | .send_request = xs_udp_send_request, |
| 1050 | .set_retrans_timeout = xprt_set_retrans_timeout_rtt, | 1051 | .set_retrans_timeout = xprt_set_retrans_timeout_rtt, |
| @@ -1054,6 +1055,7 @@ static struct rpc_xprt_ops xs_udp_ops = { | |||
| 1054 | 1055 | ||
| 1055 | static struct rpc_xprt_ops xs_tcp_ops = { | 1056 | static struct rpc_xprt_ops xs_tcp_ops = { |
| 1056 | .set_buffer_size = xs_tcp_set_buffer_size, | 1057 | .set_buffer_size = xs_tcp_set_buffer_size, |
| 1058 | .reserve_xprt = xprt_reserve_xprt, | ||
| 1057 | .connect = xs_connect, | 1059 | .connect = xs_connect, |
| 1058 | .send_request = xs_tcp_send_request, | 1060 | .send_request = xs_tcp_send_request, |
| 1059 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 1061 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
