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

Commit f9773b22 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

Merge tag 'nfs-rdma-for-4.14-1' of git://git.linux-nfs.org/projects/anna/linux-nfs into linux-next

NFS-over-RDMA client updates for Linux 4.14

Bugfixes and cleanups:
- Constify rpc_xprt_ops
- Harden RPC call encoding and decoding
- Clean up rpc call decoding to use xdr_streams
- Remove unused variables from various structures
- Refactor code to remove imul instructions
- Rearrange rx_stats structure for better cacheline sharing
parents 7af7a596 67af6f65
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -239,6 +239,19 @@ extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);


/**
 * xdr_stream_remaining - Return the number of bytes remaining in the stream
 * @xdr: pointer to struct xdr_stream
 *
 * Return value:
 *   Number of bytes remaining in @xdr before xdr->end
 */
static inline size_t
xdr_stream_remaining(const struct xdr_stream *xdr)
{
	return xdr->nwords << 2;
}

ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
		size_t maxlen, gfp_t gfp_flags);
		size_t maxlen, gfp_t gfp_flags);
/**
/**
+1 −1
Original line number Original line Diff line number Diff line
@@ -174,7 +174,7 @@ enum xprt_transports {


struct rpc_xprt {
struct rpc_xprt {
	struct kref		kref;		/* Reference count */
	struct kref		kref;		/* Reference count */
	struct rpc_xprt_ops *	ops;		/* transport methods */
	const struct rpc_xprt_ops *ops;		/* transport methods */


	const struct rpc_timeout *timeout;	/* timeout parms */
	const struct rpc_timeout *timeout;	/* timeout parms */
	struct sockaddr_storage	addr;		/* server address */
	struct sockaddr_storage	addr;		/* server address */
+27 −44
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ static int rpcrdma_bc_setup_rqst(struct rpcrdma_xprt *r_xprt,
	if (IS_ERR(rb))
	if (IS_ERR(rb))
		goto out_fail;
		goto out_fail;
	req->rl_rdmabuf = rb;
	req->rl_rdmabuf = rb;
	xdr_buf_init(&req->rl_hdrbuf, rb->rg_base, rdmab_length(rb));


	size = r_xprt->rx_data.inline_rsize;
	size = r_xprt->rx_data.inline_rsize;
	rb = rpcrdma_alloc_regbuf(size, DMA_TO_DEVICE, GFP_KERNEL);
	rb = rpcrdma_alloc_regbuf(size, DMA_TO_DEVICE, GFP_KERNEL);
@@ -202,20 +203,24 @@ size_t xprt_rdma_bc_maxpayload(struct rpc_xprt *xprt)
 */
 */
int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
{
{
	struct rpc_xprt *xprt = rqst->rq_xprt;
	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
	struct rpcrdma_msg *headerp;
	__be32 *p;


	headerp = rdmab_to_msg(req->rl_rdmabuf);
	rpcrdma_set_xdrlen(&req->rl_hdrbuf, 0);
	headerp->rm_xid = rqst->rq_xid;
	xdr_init_encode(&req->rl_stream, &req->rl_hdrbuf,
	headerp->rm_vers = rpcrdma_version;
			req->rl_rdmabuf->rg_base);
	headerp->rm_credit =

			cpu_to_be32(r_xprt->rx_buf.rb_bc_srv_max_requests);
	p = xdr_reserve_space(&req->rl_stream, 28);
	headerp->rm_type = rdma_msg;
	if (unlikely(!p))
	headerp->rm_body.rm_chunks[0] = xdr_zero;
		return -EIO;
	headerp->rm_body.rm_chunks[1] = xdr_zero;
	*p++ = rqst->rq_xid;
	headerp->rm_body.rm_chunks[2] = xdr_zero;
	*p++ = rpcrdma_version;
	*p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_srv_max_requests);
	*p++ = rdma_msg;
	*p++ = xdr_zero;
	*p++ = xdr_zero;
	*p = xdr_zero;


	if (!rpcrdma_prepare_send_sges(&r_xprt->rx_ia, req, RPCRDMA_HDRLEN_MIN,
	if (!rpcrdma_prepare_send_sges(&r_xprt->rx_ia, req, RPCRDMA_HDRLEN_MIN,
				       &rqst->rq_snd_buf, rpcrdma_noch))
				       &rqst->rq_snd_buf, rpcrdma_noch))
@@ -271,9 +276,6 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst)
 * @xprt: transport receiving the call
 * @xprt: transport receiving the call
 * @rep: receive buffer containing the call
 * @rep: receive buffer containing the call
 *
 *
 * Called in the RPC reply handler, which runs in a tasklet.
 * Be quick about it.
 *
 * Operational assumptions:
 * Operational assumptions:
 *    o Backchannel credits are ignored, just as the NFS server
 *    o Backchannel credits are ignored, just as the NFS server
 *      forechannel currently does
 *      forechannel currently does
@@ -284,7 +286,6 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
			     struct rpcrdma_rep *rep)
			     struct rpcrdma_rep *rep)
{
{
	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
	struct rpcrdma_msg *headerp;
	struct svc_serv *bc_serv;
	struct svc_serv *bc_serv;
	struct rpcrdma_req *req;
	struct rpcrdma_req *req;
	struct rpc_rqst *rqst;
	struct rpc_rqst *rqst;
@@ -292,24 +293,15 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
	size_t size;
	size_t size;
	__be32 *p;
	__be32 *p;


	headerp = rdmab_to_msg(rep->rr_rdmabuf);
	p = xdr_inline_decode(&rep->rr_stream, 0);
	size = xdr_stream_remaining(&rep->rr_stream);

#ifdef RPCRDMA_BACKCHANNEL_DEBUG
#ifdef RPCRDMA_BACKCHANNEL_DEBUG
	pr_info("RPC:       %s: callback XID %08x, length=%u\n",
	pr_info("RPC:       %s: callback XID %08x, length=%u\n",
		__func__, be32_to_cpu(headerp->rm_xid), rep->rr_len);
		__func__, be32_to_cpup(p), size);
	pr_info("RPC:       %s: %*ph\n", __func__, rep->rr_len, headerp);
	pr_info("RPC:       %s: %*ph\n", __func__, size, p);
#endif
#endif


	/* Sanity check:
	 * Need at least enough bytes for RPC/RDMA header, as code
	 * here references the header fields by array offset. Also,
	 * backward calls are always inline, so ensure there
	 * are some bytes beyond the RPC/RDMA header.
	 */
	if (rep->rr_len < RPCRDMA_HDRLEN_MIN + 24)
		goto out_short;
	p = (__be32 *)((unsigned char *)headerp + RPCRDMA_HDRLEN_MIN);
	size = rep->rr_len - RPCRDMA_HDRLEN_MIN;

	/* Grab a free bc rqst */
	/* Grab a free bc rqst */
	spin_lock(&xprt->bc_pa_lock);
	spin_lock(&xprt->bc_pa_lock);
	if (list_empty(&xprt->bc_pa_list)) {
	if (list_empty(&xprt->bc_pa_list)) {
@@ -325,7 +317,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
	/* Prepare rqst */
	/* Prepare rqst */
	rqst->rq_reply_bytes_recvd = 0;
	rqst->rq_reply_bytes_recvd = 0;
	rqst->rq_bytes_sent = 0;
	rqst->rq_bytes_sent = 0;
	rqst->rq_xid = headerp->rm_xid;
	rqst->rq_xid = *p;


	rqst->rq_private_buf.len = size;
	rqst->rq_private_buf.len = size;
	set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state);
	set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state);
@@ -337,9 +329,9 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
	buf->len = size;
	buf->len = size;


	/* The receive buffer has to be hooked to the rpcrdma_req
	/* The receive buffer has to be hooked to the rpcrdma_req
	 * so that it can be reposted after the server is done
	 * so that it is not released while the req is pointing
	 * parsing it but just before sending the backward
	 * to its buffer, and so that it can be reposted after
	 * direction reply.
	 * the Upper Layer is done decoding it.
	 */
	 */
	req = rpcr_to_rdmar(rqst);
	req = rpcr_to_rdmar(rqst);
	dprintk("RPC:       %s: attaching rep %p to req %p\n",
	dprintk("RPC:       %s: attaching rep %p to req %p\n",
@@ -367,13 +359,4 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
	 * when the connection is re-established.
	 * when the connection is re-established.
	 */
	 */
	return;
	return;

out_short:
	pr_warn("RPC/RDMA short backward direction call\n");

	if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, rep))
		xprt_disconnect_done(xprt);
	else
		pr_warn("RPC:       %s: reposting rep %p\n",
			__func__, rep);
}
}
+5 −5
Original line number Original line Diff line number Diff line
@@ -177,7 +177,7 @@ fmr_op_maxpages(struct rpcrdma_xprt *r_xprt)
/* Use the ib_map_phys_fmr() verb to register a memory region
/* Use the ib_map_phys_fmr() verb to register a memory region
 * for remote access via RDMA READ or RDMA WRITE.
 * for remote access via RDMA READ or RDMA WRITE.
 */
 */
static int
static struct rpcrdma_mr_seg *
fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
	   int nsegs, bool writing, struct rpcrdma_mw **out)
	   int nsegs, bool writing, struct rpcrdma_mw **out)
{
{
@@ -188,7 +188,7 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,


	mw = rpcrdma_get_mw(r_xprt);
	mw = rpcrdma_get_mw(r_xprt);
	if (!mw)
	if (!mw)
		return -ENOBUFS;
		return ERR_PTR(-ENOBUFS);


	pageoff = offset_in_page(seg1->mr_offset);
	pageoff = offset_in_page(seg1->mr_offset);
	seg1->mr_offset -= pageoff;	/* start of page */
	seg1->mr_offset -= pageoff;	/* start of page */
@@ -232,13 +232,13 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
	mw->mw_offset = dma_pages[0] + pageoff;
	mw->mw_offset = dma_pages[0] + pageoff;


	*out = mw;
	*out = mw;
	return mw->mw_nents;
	return seg;


out_dmamap_err:
out_dmamap_err:
	pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
	pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
	       mw->mw_sg, i);
	       mw->mw_sg, i);
	rpcrdma_put_mw(r_xprt, mw);
	rpcrdma_put_mw(r_xprt, mw);
	return -EIO;
	return ERR_PTR(-EIO);


out_maperr:
out_maperr:
	pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n",
	pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n",
@@ -247,7 +247,7 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
	ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
	ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
			mw->mw_sg, mw->mw_nents, mw->mw_dir);
			mw->mw_sg, mw->mw_nents, mw->mw_dir);
	rpcrdma_put_mw(r_xprt, mw);
	rpcrdma_put_mw(r_xprt, mw);
	return -EIO;
	return ERR_PTR(-EIO);
}
}


/* Invalidate all memory regions that were registered for "req".
/* Invalidate all memory regions that were registered for "req".
+6 −6
Original line number Original line Diff line number Diff line
@@ -344,7 +344,7 @@ frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
/* Post a REG_MR Work Request to register a memory region
/* Post a REG_MR Work Request to register a memory region
 * for remote access via RDMA READ or RDMA WRITE.
 * for remote access via RDMA READ or RDMA WRITE.
 */
 */
static int
static struct rpcrdma_mr_seg *
frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
	    int nsegs, bool writing, struct rpcrdma_mw **out)
	    int nsegs, bool writing, struct rpcrdma_mw **out)
{
{
@@ -364,7 +364,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
			rpcrdma_defer_mr_recovery(mw);
			rpcrdma_defer_mr_recovery(mw);
		mw = rpcrdma_get_mw(r_xprt);
		mw = rpcrdma_get_mw(r_xprt);
		if (!mw)
		if (!mw)
			return -ENOBUFS;
			return ERR_PTR(-ENOBUFS);
	} while (mw->frmr.fr_state != FRMR_IS_INVALID);
	} while (mw->frmr.fr_state != FRMR_IS_INVALID);
	frmr = &mw->frmr;
	frmr = &mw->frmr;
	frmr->fr_state = FRMR_IS_VALID;
	frmr->fr_state = FRMR_IS_VALID;
@@ -429,25 +429,25 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
	mw->mw_offset = mr->iova;
	mw->mw_offset = mr->iova;


	*out = mw;
	*out = mw;
	return mw->mw_nents;
	return seg;


out_dmamap_err:
out_dmamap_err:
	pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
	pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n",
	       mw->mw_sg, i);
	       mw->mw_sg, i);
	frmr->fr_state = FRMR_IS_INVALID;
	frmr->fr_state = FRMR_IS_INVALID;
	rpcrdma_put_mw(r_xprt, mw);
	rpcrdma_put_mw(r_xprt, mw);
	return -EIO;
	return ERR_PTR(-EIO);


out_mapmr_err:
out_mapmr_err:
	pr_err("rpcrdma: failed to map mr %p (%d/%d)\n",
	pr_err("rpcrdma: failed to map mr %p (%d/%d)\n",
	       frmr->fr_mr, n, mw->mw_nents);
	       frmr->fr_mr, n, mw->mw_nents);
	rpcrdma_defer_mr_recovery(mw);
	rpcrdma_defer_mr_recovery(mw);
	return -EIO;
	return ERR_PTR(-EIO);


out_senderr:
out_senderr:
	pr_err("rpcrdma: FRMR registration ib_post_send returned %i\n", rc);
	pr_err("rpcrdma: FRMR registration ib_post_send returned %i\n", rc);
	rpcrdma_defer_mr_recovery(mw);
	rpcrdma_defer_mr_recovery(mw);
	return -ENOTCONN;
	return ERR_PTR(-ENOTCONN);
}
}


/* Invalidate all memory regions that were registered for "req".
/* Invalidate all memory regions that were registered for "req".
Loading