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>
This commit is contained in:
parent
d8647f2d3c
commit
59aa1f9a3c
|
@ -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 {
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ badheader:
|
||||||
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 @@ out_bcall:
|
||||||
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:
|
||||||
|
|
Loading…
Reference in New Issue