diff options
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_sendto.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 0b646e8f23c7..e514f6864a93 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -621,6 +621,48 @@ err: return ret; } +/* Given the client-provided Write and Reply chunks, the server was not + * able to form a complete reply. Return an RDMA_ERROR message so the + * client can retire this RPC transaction. As above, the Send completion + * routine releases payload pages that were part of a previous RDMA Write. + * + * Remote Invalidation is skipped for simplicity. + */ +static int svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, + __be32 *rdma_resp, struct svc_rqst *rqstp) +{ + struct svc_rdma_op_ctxt *ctxt; + __be32 *p; + int ret; + + ctxt = svc_rdma_get_context(rdma); + + /* Replace the original transport header with an + * RDMA_ERROR response. XID etc are preserved. + */ + p = rdma_resp + 3; + *p++ = rdma_error; + *p = err_chunk; + + ret = svc_rdma_map_reply_hdr(rdma, ctxt, rdma_resp, 20); + if (ret < 0) + goto err; + + svc_rdma_save_io_pages(rqstp, ctxt); + + ret = svc_rdma_post_send_wr(rdma, ctxt, 1 + ret, 0); + if (ret) + goto err; + + return 0; + +err: + pr_err("svcrdma: failed to post Send WR (%d)\n", ret); + svc_rdma_unmap_dma(ctxt); + svc_rdma_put_context(ctxt, 1); + return ret; +} + void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp) { } @@ -683,13 +725,13 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) /* XXX: Presume the client sent only one Write chunk */ ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr); if (ret < 0) - goto err1; + goto err2; svc_rdma_xdr_encode_write_list(rdma_resp, wr_lst, ret); } if (rp_ch) { ret = svc_rdma_send_reply_chunk(rdma, rp_ch, wr_lst, xdr); if (ret < 0) - goto err1; + goto err2; svc_rdma_xdr_encode_reply_chunk(rdma_resp, rp_ch, ret); } @@ -702,6 +744,18 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) goto err0; return 0; + err2: + if (ret != -E2BIG) + goto err1; + + ret = svc_rdma_post_recv(rdma, GFP_KERNEL); + if (ret) + goto err1; + ret = svc_rdma_send_error_msg(rdma, rdma_resp, rqstp); + if (ret < 0) + goto err0; + return 0; + err1: put_page(res_page); err0: |