Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -93,6 +93,12 @@ struct rpcrdma_msg {
			__be32 rm_pempty[3];	/* 3 empty chunk lists */
		} 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 */

	} rm_body;
@@ -109,11 +115,6 @@ enum rpcrdma_errcode {
	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 {
	RDMA_MSG = 0,		/* An RPC call or reply msg */
	RDMA_NOMSG = 1,		/* An RPC call or reply msg - separate body */
+43 −8
Original line number Diff line number Diff line
@@ -795,7 +795,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
	struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
	__be32 *iptr;
	int rdmalen, status;
	int rdmalen, status, rmerr;
	unsigned long cwnd;
	u32 credits;

@@ -803,12 +803,10 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)

	if (rep->rr_len == RPCRDMA_BAD_LEN)
		goto out_badstatus;
	if (rep->rr_len < RPCRDMA_HDRLEN_MIN)
	if (rep->rr_len < RPCRDMA_HDRLEN_ERR)
		goto out_shortreply;

	headerp = rdmab_to_msg(rep->rr_rdmabuf);
	if (headerp->rm_vers != rpcrdma_version)
		goto out_badversion;
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
	if (rpcrdma_is_bcall(headerp))
		goto out_bcall;
@@ -838,6 +836,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
	req->rl_reply = rep;
	xprt->reestablish_timeout = 0;

	if (headerp->rm_vers != rpcrdma_version)
		goto out_badversion;

	/* check for expected message types */
	/* The order of some of these tests is important. */
	switch (headerp->rm_type) {
@@ -898,6 +899,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
		status = rdmalen;
		break;

	case rdma_error:
		goto out_rdmaerr;

badheader:
	default:
		dprintk("%s: invalid rpcrdma reply header (type %d):"
@@ -913,6 +917,7 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
		break;
	}

out:
	/* Invalidate and flush the data payloads before waking the
	 * waiting application. This guarantees the memory region is
	 * properly fenced from the server before the application
@@ -955,13 +960,43 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
	return;
#endif

out_shortreply:
	dprintk("RPC:       %s: short/invalid reply\n", __func__);
	goto repost;

/* If the incoming reply terminated a pending RPC, the next
 * RPC call will post a replacement receive buffer as it is
 * being marshaled.
 */
out_badversion:
	dprintk("RPC:       %s: invalid version %d\n",
		__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;

out_nomatch: