diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 143 |
1 files changed, 136 insertions, 7 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5abab094441f..5bc2f45bddf0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -36,7 +36,9 @@ | |||
36 | #include <linux/sunrpc/clnt.h> | 36 | #include <linux/sunrpc/clnt.h> |
37 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
38 | #include <linux/sunrpc/metrics.h> | 38 | #include <linux/sunrpc/metrics.h> |
39 | #include <linux/sunrpc/bc_xprt.h> | ||
39 | 40 | ||
41 | #include "sunrpc.h" | ||
40 | 42 | ||
41 | #ifdef RPC_DEBUG | 43 | #ifdef RPC_DEBUG |
42 | # define RPCDBG_FACILITY RPCDBG_CALL | 44 | # define RPCDBG_FACILITY RPCDBG_CALL |
@@ -63,6 +65,9 @@ static void call_decode(struct rpc_task *task); | |||
63 | static void call_bind(struct rpc_task *task); | 65 | static void call_bind(struct rpc_task *task); |
64 | static void call_bind_status(struct rpc_task *task); | 66 | static void call_bind_status(struct rpc_task *task); |
65 | static void call_transmit(struct rpc_task *task); | 67 | static void call_transmit(struct rpc_task *task); |
68 | #if defined(CONFIG_NFS_V4_1) | ||
69 | static void call_bc_transmit(struct rpc_task *task); | ||
70 | #endif /* CONFIG_NFS_V4_1 */ | ||
66 | static void call_status(struct rpc_task *task); | 71 | static void call_status(struct rpc_task *task); |
67 | static void call_transmit_status(struct rpc_task *task); | 72 | static void call_transmit_status(struct rpc_task *task); |
68 | static void call_refresh(struct rpc_task *task); | 73 | static void call_refresh(struct rpc_task *task); |
@@ -613,6 +618,50 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, | |||
613 | } | 618 | } |
614 | EXPORT_SYMBOL_GPL(rpc_call_async); | 619 | EXPORT_SYMBOL_GPL(rpc_call_async); |
615 | 620 | ||
621 | #if defined(CONFIG_NFS_V4_1) | ||
622 | /** | ||
623 | * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run | ||
624 | * rpc_execute against it | ||
625 | * @ops: RPC call ops | ||
626 | */ | ||
627 | struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | ||
628 | const struct rpc_call_ops *tk_ops) | ||
629 | { | ||
630 | struct rpc_task *task; | ||
631 | struct xdr_buf *xbufp = &req->rq_snd_buf; | ||
632 | struct rpc_task_setup task_setup_data = { | ||
633 | .callback_ops = tk_ops, | ||
634 | }; | ||
635 | |||
636 | dprintk("RPC: rpc_run_bc_task req= %p\n", req); | ||
637 | /* | ||
638 | * Create an rpc_task to send the data | ||
639 | */ | ||
640 | task = rpc_new_task(&task_setup_data); | ||
641 | if (!task) { | ||
642 | xprt_free_bc_request(req); | ||
643 | goto out; | ||
644 | } | ||
645 | task->tk_rqstp = req; | ||
646 | |||
647 | /* | ||
648 | * Set up the xdr_buf length. | ||
649 | * This also indicates that the buffer is XDR encoded already. | ||
650 | */ | ||
651 | xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + | ||
652 | xbufp->tail[0].iov_len; | ||
653 | |||
654 | task->tk_action = call_bc_transmit; | ||
655 | atomic_inc(&task->tk_count); | ||
656 | BUG_ON(atomic_read(&task->tk_count) != 2); | ||
657 | rpc_execute(task); | ||
658 | |||
659 | out: | ||
660 | dprintk("RPC: rpc_run_bc_task: task= %p\n", task); | ||
661 | return task; | ||
662 | } | ||
663 | #endif /* CONFIG_NFS_V4_1 */ | ||
664 | |||
616 | void | 665 | void |
617 | rpc_call_start(struct rpc_task *task) | 666 | rpc_call_start(struct rpc_task *task) |
618 | { | 667 | { |
@@ -695,6 +744,19 @@ void rpc_force_rebind(struct rpc_clnt *clnt) | |||
695 | EXPORT_SYMBOL_GPL(rpc_force_rebind); | 744 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
696 | 745 | ||
697 | /* | 746 | /* |
747 | * Restart an (async) RPC call from the call_prepare state. | ||
748 | * Usually called from within the exit handler. | ||
749 | */ | ||
750 | void | ||
751 | rpc_restart_call_prepare(struct rpc_task *task) | ||
752 | { | ||
753 | if (RPC_ASSASSINATED(task)) | ||
754 | return; | ||
755 | task->tk_action = rpc_prepare_task; | ||
756 | } | ||
757 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | ||
758 | |||
759 | /* | ||
698 | * Restart an (async) RPC call. Usually called from within the | 760 | * Restart an (async) RPC call. Usually called from within the |
699 | * exit handler. | 761 | * exit handler. |
700 | */ | 762 | */ |
@@ -1085,7 +1147,7 @@ call_transmit(struct rpc_task *task) | |||
1085 | * in order to allow access to the socket to other RPC requests. | 1147 | * in order to allow access to the socket to other RPC requests. |
1086 | */ | 1148 | */ |
1087 | call_transmit_status(task); | 1149 | call_transmit_status(task); |
1088 | if (task->tk_msg.rpc_proc->p_decode != NULL) | 1150 | if (rpc_reply_expected(task)) |
1089 | return; | 1151 | return; |
1090 | task->tk_action = rpc_exit_task; | 1152 | task->tk_action = rpc_exit_task; |
1091 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); | 1153 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); |
@@ -1120,6 +1182,72 @@ call_transmit_status(struct rpc_task *task) | |||
1120 | } | 1182 | } |
1121 | } | 1183 | } |
1122 | 1184 | ||
1185 | #if defined(CONFIG_NFS_V4_1) | ||
1186 | /* | ||
1187 | * 5b. Send the backchannel RPC reply. On error, drop the reply. In | ||
1188 | * addition, disconnect on connectivity errors. | ||
1189 | */ | ||
1190 | static void | ||
1191 | call_bc_transmit(struct rpc_task *task) | ||
1192 | { | ||
1193 | struct rpc_rqst *req = task->tk_rqstp; | ||
1194 | |||
1195 | BUG_ON(task->tk_status != 0); | ||
1196 | task->tk_status = xprt_prepare_transmit(task); | ||
1197 | if (task->tk_status == -EAGAIN) { | ||
1198 | /* | ||
1199 | * Could not reserve the transport. Try again after the | ||
1200 | * transport is released. | ||
1201 | */ | ||
1202 | task->tk_status = 0; | ||
1203 | task->tk_action = call_bc_transmit; | ||
1204 | return; | ||
1205 | } | ||
1206 | |||
1207 | task->tk_action = rpc_exit_task; | ||
1208 | if (task->tk_status < 0) { | ||
1209 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
1210 | "error: %d\n", task->tk_status); | ||
1211 | return; | ||
1212 | } | ||
1213 | |||
1214 | xprt_transmit(task); | ||
1215 | xprt_end_transmit(task); | ||
1216 | dprint_status(task); | ||
1217 | switch (task->tk_status) { | ||
1218 | case 0: | ||
1219 | /* Success */ | ||
1220 | break; | ||
1221 | case -EHOSTDOWN: | ||
1222 | case -EHOSTUNREACH: | ||
1223 | case -ENETUNREACH: | ||
1224 | case -ETIMEDOUT: | ||
1225 | /* | ||
1226 | * Problem reaching the server. Disconnect and let the | ||
1227 | * forechannel reestablish the connection. The server will | ||
1228 | * have to retransmit the backchannel request and we'll | ||
1229 | * reprocess it. Since these ops are idempotent, there's no | ||
1230 | * need to cache our reply at this time. | ||
1231 | */ | ||
1232 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
1233 | "error: %d\n", task->tk_status); | ||
1234 | xprt_conditional_disconnect(task->tk_xprt, | ||
1235 | req->rq_connect_cookie); | ||
1236 | break; | ||
1237 | default: | ||
1238 | /* | ||
1239 | * We were unable to reply and will have to drop the | ||
1240 | * request. The server should reconnect and retransmit. | ||
1241 | */ | ||
1242 | BUG_ON(task->tk_status == -EAGAIN); | ||
1243 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
1244 | "error: %d\n", task->tk_status); | ||
1245 | break; | ||
1246 | } | ||
1247 | rpc_wake_up_queued_task(&req->rq_xprt->pending, task); | ||
1248 | } | ||
1249 | #endif /* CONFIG_NFS_V4_1 */ | ||
1250 | |||
1123 | /* | 1251 | /* |
1124 | * 6. Sort out the RPC call status | 1252 | * 6. Sort out the RPC call status |
1125 | */ | 1253 | */ |
@@ -1130,8 +1258,8 @@ call_status(struct rpc_task *task) | |||
1130 | struct rpc_rqst *req = task->tk_rqstp; | 1258 | struct rpc_rqst *req = task->tk_rqstp; |
1131 | int status; | 1259 | int status; |
1132 | 1260 | ||
1133 | if (req->rq_received > 0 && !req->rq_bytes_sent) | 1261 | if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) |
1134 | task->tk_status = req->rq_received; | 1262 | task->tk_status = req->rq_reply_bytes_recvd; |
1135 | 1263 | ||
1136 | dprint_status(task); | 1264 | dprint_status(task); |
1137 | 1265 | ||
@@ -1248,7 +1376,7 @@ call_decode(struct rpc_task *task) | |||
1248 | 1376 | ||
1249 | /* | 1377 | /* |
1250 | * Ensure that we see all writes made by xprt_complete_rqst() | 1378 | * Ensure that we see all writes made by xprt_complete_rqst() |
1251 | * before it changed req->rq_received. | 1379 | * before it changed req->rq_reply_bytes_recvd. |
1252 | */ | 1380 | */ |
1253 | smp_rmb(); | 1381 | smp_rmb(); |
1254 | req->rq_rcv_buf.len = req->rq_private_buf.len; | 1382 | req->rq_rcv_buf.len = req->rq_private_buf.len; |
@@ -1289,7 +1417,7 @@ out_retry: | |||
1289 | task->tk_status = 0; | 1417 | task->tk_status = 0; |
1290 | /* Note: rpc_verify_header() may have freed the RPC slot */ | 1418 | /* Note: rpc_verify_header() may have freed the RPC slot */ |
1291 | if (task->tk_rqstp == req) { | 1419 | if (task->tk_rqstp == req) { |
1292 | req->rq_received = req->rq_rcv_buf.len = 0; | 1420 | req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0; |
1293 | if (task->tk_client->cl_discrtry) | 1421 | if (task->tk_client->cl_discrtry) |
1294 | xprt_conditional_disconnect(task->tk_xprt, | 1422 | xprt_conditional_disconnect(task->tk_xprt, |
1295 | req->rq_connect_cookie); | 1423 | req->rq_connect_cookie); |
@@ -1377,13 +1505,14 @@ rpc_verify_header(struct rpc_task *task) | |||
1377 | } | 1505 | } |
1378 | if ((len -= 3) < 0) | 1506 | if ((len -= 3) < 0) |
1379 | goto out_overflow; | 1507 | goto out_overflow; |
1380 | p += 1; /* skip XID */ | ||
1381 | 1508 | ||
1509 | p += 1; /* skip XID */ | ||
1382 | if ((n = ntohl(*p++)) != RPC_REPLY) { | 1510 | if ((n = ntohl(*p++)) != RPC_REPLY) { |
1383 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", | 1511 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", |
1384 | task->tk_pid, __func__, n); | 1512 | task->tk_pid, __func__, n); |
1385 | goto out_garbage; | 1513 | goto out_garbage; |
1386 | } | 1514 | } |
1515 | |||
1387 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { | 1516 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { |
1388 | if (--len < 0) | 1517 | if (--len < 0) |
1389 | goto out_overflow; | 1518 | goto out_overflow; |