Commit 59aa1f9a authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker

xprtrdma: Properly handle RDMA_ERROR replies

These are shorter than RPCRDMA_HDRLEN_MIN, and they need to
complete the waiting RPC.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Reviewed-by: default avatarSagi Grimberg <sagig@mellanox.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent d8647f2d
...@@ -93,6 +93,12 @@ struct rpcrdma_msg { ...@@ -93,6 +93,12 @@ struct rpcrdma_msg {
__be32 rm_pempty[3]; /* 3 empty chunk lists */ __be32 rm_pempty[3]; /* 3 empty chunk lists */
} rm_padded; } rm_padded;
struct {
__be32 rm_err;
__be32 rm_vers_low;
__be32 rm_vers_high;
} rm_error;
__be32 rm_chunks[0]; /* read, write and reply chunks */ __be32 rm_chunks[0]; /* read, write and reply chunks */
} rm_body; } rm_body;
...@@ -109,11 +115,6 @@ enum rpcrdma_errcode { ...@@ -109,11 +115,6 @@ enum rpcrdma_errcode {
ERR_CHUNK = 2 ERR_CHUNK = 2
}; };
struct rpcrdma_err_vers {
uint32_t rdma_vers_low; /* Version range supported by peer */
uint32_t rdma_vers_high;
};
enum rpcrdma_proc { enum rpcrdma_proc {
RDMA_MSG = 0, /* An RPC call or reply msg */ RDMA_MSG = 0, /* An RPC call or reply msg */
RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */ RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */
......
...@@ -795,7 +795,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -795,7 +795,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
struct rpc_xprt *xprt = &r_xprt->rx_xprt; struct rpc_xprt *xprt = &r_xprt->rx_xprt;
__be32 *iptr; __be32 *iptr;
int rdmalen, status; int rdmalen, status, rmerr;
unsigned long cwnd; unsigned long cwnd;
u32 credits; u32 credits;
...@@ -803,12 +803,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -803,12 +803,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
if (rep->rr_len == RPCRDMA_BAD_LEN) if (rep->rr_len == RPCRDMA_BAD_LEN)
goto out_badstatus; goto out_badstatus;
if (rep->rr_len < RPCRDMA_HDRLEN_MIN) if (rep->rr_len < RPCRDMA_HDRLEN_ERR)
goto out_shortreply; goto out_shortreply;
headerp = rdmab_to_msg(rep->rr_rdmabuf); headerp = rdmab_to_msg(rep->rr_rdmabuf);
if (headerp->rm_vers != rpcrdma_version)
goto out_badversion;
#if defined(CONFIG_SUNRPC_BACKCHANNEL) #if defined(CONFIG_SUNRPC_BACKCHANNEL)
if (rpcrdma_is_bcall(headerp)) if (rpcrdma_is_bcall(headerp))
goto out_bcall; goto out_bcall;
...@@ -838,6 +836,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -838,6 +836,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
req->rl_reply = rep; req->rl_reply = rep;
xprt->reestablish_timeout = 0; xprt->reestablish_timeout = 0;
if (headerp->rm_vers != rpcrdma_version)
goto out_badversion;
/* check for expected message types */ /* check for expected message types */
/* The order of some of these tests is important. */ /* The order of some of these tests is important. */
switch (headerp->rm_type) { switch (headerp->rm_type) {
...@@ -898,6 +899,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -898,6 +899,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
status = rdmalen; status = rdmalen;
break; break;
case rdma_error:
goto out_rdmaerr;
badheader: badheader:
default: default:
dprintk("%s: invalid rpcrdma reply header (type %d):" dprintk("%s: invalid rpcrdma reply header (type %d):"
...@@ -913,6 +917,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -913,6 +917,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
break; break;
} }
out:
/* Invalidate and flush the data payloads before waking the /* Invalidate and flush the data payloads before waking the
* waiting application. This guarantees the memory region is * waiting application. This guarantees the memory region is
* properly fenced from the server before the application * properly fenced from the server before the application
...@@ -955,13 +960,43 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep) ...@@ -955,13 +960,43 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
return; return;
#endif #endif
out_shortreply: /* If the incoming reply terminated a pending RPC, the next
dprintk("RPC: %s: short/invalid reply\n", __func__); * RPC call will post a replacement receive buffer as it is
goto repost; * being marshaled.
*/
out_badversion: out_badversion:
dprintk("RPC: %s: invalid version %d\n", dprintk("RPC: %s: invalid version %d\n",
__func__, be32_to_cpu(headerp->rm_vers)); __func__, be32_to_cpu(headerp->rm_vers));
status = -EIO;
r_xprt->rx_stats.bad_reply_count++;
goto out;
out_rdmaerr:
rmerr = be32_to_cpu(headerp->rm_body.rm_error.rm_err);
switch (rmerr) {
case ERR_VERS:
pr_err("%s: server reports header version error (%u-%u)\n",
__func__,
be32_to_cpu(headerp->rm_body.rm_error.rm_vers_low),
be32_to_cpu(headerp->rm_body.rm_error.rm_vers_high));
break;
case ERR_CHUNK:
pr_err("%s: server reports header decoding error\n",
__func__);
break;
default:
pr_err("%s: server reports unknown error %d\n",
__func__, rmerr);
}
status = -EREMOTEIO;
r_xprt->rx_stats.bad_reply_count++;
goto out;
/* If no pending RPC transaction was matched, post a replacement
* receive buffer before returning.
*/
out_shortreply:
dprintk("RPC: %s: short/invalid reply\n", __func__);
goto repost; goto repost;
out_nomatch: out_nomatch:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment