diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2016-03-04 11:28:18 -0500 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2016-03-14 14:55:59 -0400 |
commit | 59aa1f9a3cce388b4d7d842d6963df11d92a407e (patch) | |
tree | 65778460b9050948004b79b65b95a23b8faf840d | |
parent | d8647f2d3c381a6f543358710eb07dafa7070854 (diff) |
xprtrdma: Properly handle RDMA_ERROR replies
These are shorter than RPCRDMA_HDRLEN_MIN, and they need to
complete the waiting RPC.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | include/linux/sunrpc/rpc_rdma.h | 11 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 51 |
2 files changed, 49 insertions, 13 deletions
diff --git a/include/linux/sunrpc/rpc_rdma.h b/include/linux/sunrpc/rpc_rdma.h index 8c6d23cb0cae..3b1ff38f0c37 100644 --- a/include/linux/sunrpc/rpc_rdma.h +++ b/include/linux/sunrpc/rpc_rdma.h | |||
@@ -93,6 +93,12 @@ struct rpcrdma_msg { | |||
93 | __be32 rm_pempty[3]; /* 3 empty chunk lists */ | 93 | __be32 rm_pempty[3]; /* 3 empty chunk lists */ |
94 | } rm_padded; | 94 | } rm_padded; |
95 | 95 | ||
96 | struct { | ||
97 | __be32 rm_err; | ||
98 | __be32 rm_vers_low; | ||
99 | __be32 rm_vers_high; | ||
100 | } rm_error; | ||
101 | |||
96 | __be32 rm_chunks[0]; /* read, write and reply chunks */ | 102 | __be32 rm_chunks[0]; /* read, write and reply chunks */ |
97 | 103 | ||
98 | } rm_body; | 104 | } rm_body; |
@@ -109,11 +115,6 @@ enum rpcrdma_errcode { | |||
109 | ERR_CHUNK = 2 | 115 | ERR_CHUNK = 2 |
110 | }; | 116 | }; |
111 | 117 | ||
112 | struct rpcrdma_err_vers { | ||
113 | uint32_t rdma_vers_low; /* Version range supported by peer */ | ||
114 | uint32_t rdma_vers_high; | ||
115 | }; | ||
116 | |||
117 | enum rpcrdma_proc { | 118 | enum rpcrdma_proc { |
118 | RDMA_MSG = 0, /* An RPC call or reply msg */ | 119 | RDMA_MSG = 0, /* An RPC call or reply msg */ |
119 | RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */ | 120 | RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */ |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 060739144552..35f810899729 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
@@ -795,7 +795,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) | |||
795 | struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; | 795 | struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; |
796 | struct rpc_xprt *xprt = &r_xprt->rx_xprt; | 796 | struct rpc_xprt *xprt = &r_xprt->rx_xprt; |
797 | __be32 *iptr; | 797 | __be32 *iptr; |
798 | int rdmalen, status; | 798 | int rdmalen, status, rmerr; |
799 | unsigned long cwnd; | 799 | unsigned long cwnd; |
800 | u32 credits; | 800 | u32 credits; |
801 | 801 | ||
@@ -803,12 +803,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) | |||
803 | 803 | ||
804 | if (rep->rr_len == RPCRDMA_BAD_LEN) | 804 | if (rep->rr_len == RPCRDMA_BAD_LEN) |
805 | goto out_badstatus; | 805 | goto out_badstatus; |
806 | if (rep->rr_len < RPCRDMA_HDRLEN_MIN) | 806 | if (rep->rr_len < RPCRDMA_HDRLEN_ERR) |
807 | goto out_shortreply; | 807 | goto out_shortreply; |
808 | 808 | ||
809 | headerp = rdmab_to_msg(rep->rr_rdmabuf); | 809 | headerp = rdmab_to_msg(rep->rr_rdmabuf); |
810 | if (headerp->rm_vers != rpcrdma_version) | ||
811 | goto out_badversion; | ||
812 | #if defined(CONFIG_SUNRPC_BACKCHANNEL) | 810 | #if defined(CONFIG_SUNRPC_BACKCHANNEL) |
813 | if (rpcrdma_is_bcall(headerp)) | 811 | if (rpcrdma_is_bcall(headerp)) |
814 | goto out_bcall; | 812 | goto out_bcall; |
@@ -838,6 +836,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) | |||
838 | req->rl_reply = rep; | 836 | req->rl_reply = rep; |
839 | xprt->reestablish_timeout = 0; | 837 | xprt->reestablish_timeout = 0; |
840 | 838 | ||
839 | if (headerp->rm_vers != rpcrdma_version) | ||
840 | goto out_badversion; | ||
841 | |||
841 | /* check for expected message types */ | 842 | /* check for expected message types */ |
842 | /* The order of some of these tests is important. */ | 843 | /* The order of some of these tests is important. */ |
843 | switch (headerp->rm_type) { | 844 | switch (headerp->rm_type) { |
@@ -898,6 +899,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) | |||
898 | status = rdmalen; | 899 | status = rdmalen; |
899 | break; | 900 | break; |
900 | 901 | ||
902 | case rdma_error: | ||
903 | goto out_rdmaerr; | ||
904 | |||
901 | badheader: | 905 | badheader: |
902 | default: | 906 | default: |
903 | dprintk("%s: invalid rpcrdma reply header (type %d):" | 907 | dprintk("%s: invalid rpcrdma reply header (type %d):" |
@@ -913,6 +917,7 @@ badheader: | |||
913 | break; | 917 | break; |
914 | } | 918 | } |
915 | 919 | ||
920 | out: | ||
916 | /* Invalidate and flush the data payloads before waking the | 921 | /* Invalidate and flush the data payloads before waking the |
917 | * waiting application. This guarantees the memory region is | 922 | * waiting application. This guarantees the memory region is |
918 | * properly fenced from the server before the application | 923 | * properly fenced from the server before the application |
@@ -955,13 +960,43 @@ out_bcall: | |||
955 | return; | 960 | return; |
956 | #endif | 961 | #endif |
957 | 962 | ||
958 | out_shortreply: | 963 | /* If the incoming reply terminated a pending RPC, the next |
959 | dprintk("RPC: %s: short/invalid reply\n", __func__); | 964 | * RPC call will post a replacement receive buffer as it is |
960 | goto repost; | 965 | * being marshaled. |
961 | 966 | */ | |
962 | out_badversion: | 967 | out_badversion: |
963 | dprintk("RPC: %s: invalid version %d\n", | 968 | dprintk("RPC: %s: invalid version %d\n", |
964 | __func__, be32_to_cpu(headerp->rm_vers)); | 969 | __func__, be32_to_cpu(headerp->rm_vers)); |
970 | status = -EIO; | ||
971 | r_xprt->rx_stats.bad_reply_count++; | ||
972 | goto out; | ||
973 | |||
974 | out_rdmaerr: | ||
975 | rmerr = be32_to_cpu(headerp->rm_body.rm_error.rm_err); | ||
976 | switch (rmerr) { | ||
977 | case ERR_VERS: | ||
978 | pr_err("%s: server reports header version error (%u-%u)\n", | ||
979 | __func__, | ||
980 | be32_to_cpu(headerp->rm_body.rm_error.rm_vers_low), | ||
981 | be32_to_cpu(headerp->rm_body.rm_error.rm_vers_high)); | ||
982 | break; | ||
983 | case ERR_CHUNK: | ||
984 | pr_err("%s: server reports header decoding error\n", | ||
985 | __func__); | ||
986 | break; | ||
987 | default: | ||
988 | pr_err("%s: server reports unknown error %d\n", | ||
989 | __func__, rmerr); | ||
990 | } | ||
991 | status = -EREMOTEIO; | ||
992 | r_xprt->rx_stats.bad_reply_count++; | ||
993 | goto out; | ||
994 | |||
995 | /* If no pending RPC transaction was matched, post a replacement | ||
996 | * receive buffer before returning. | ||
997 | */ | ||
998 | out_shortreply: | ||
999 | dprintk("RPC: %s: short/invalid reply\n", __func__); | ||
965 | goto repost; | 1000 | goto repost; |
966 | 1001 | ||
967 | out_nomatch: | 1002 | out_nomatch: |