/* The client can't know how large the actual reply will be. Thus it *plansforthelargestpossiblereplyforthatparticularULP *operation.Ifthemaximumcombinedreplymessagesizeexceedsthat *limit,theclientmustprovideawritelistorareplychunkfor *thisrequest.
*/ staticbool rpcrdma_results_inline(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst)
{ return rqst->rq_rcv_buf.buflen <= r_xprt->rx_ep->re_max_inline_recv;
}
/* The client is required to provide a Reply chunk if the maximum *sizeofthenon-payloadpartoftheRPCReplyislargerthan *theinlinethreshold.
*/ staticbool
rpcrdma_nonpayload_inline(conststruct rpcrdma_xprt *r_xprt, conststruct rpc_rqst *rqst)
{ conststruct xdr_buf *buf = &rqst->rq_rcv_buf;
/* ACL likes to be lazy in allocating pages. For TCP, these *pagescanbeallocatedduringreceiveprocessing.Nottrue *forRDMA,whichmustalwaysprovisionreceivebuffers *upfront.
*/ static noinline int
rpcrdma_alloc_sparse_pages(struct xdr_buf *buf)
{ struct page **ppages; int len;
len = buf->page_len;
ppages = buf->pages + (buf->page_base >> PAGE_SHIFT); while (len > 0) { if (!*ppages)
*ppages = alloc_page(GFP_NOWAIT | __GFP_NOWARN); if (!*ppages) return -ENOBUFS;
ppages++;
len -= PAGE_SIZE;
}
/* Convert @xdrbuf into SGEs no larger than a page each. As they *areregistered,theseSGEsarethencoalescedintoRDMAsegments *whentheselectedmemregmodesupportsit. * *ReturnspositivenumberofSGEsconsumed,oranegativeerrno.
*/
seg = req->rl_segments;
nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf,
rqst->rq_rcv_buf.head[0].iov_len,
wtype, seg); if (nsegs < 0) return nsegs;
if (xdr_stream_encode_item_present(xdr) < 0) return -EMSGSIZE;
segcount = xdr_reserve_space(xdr, sizeof(*segcount)); if (unlikely(!segcount)) return -EMSGSIZE; /* Actual value encoded below */
nchunks = 0; do {
seg = rpcrdma_mr_prepare(r_xprt, req, seg, nsegs, true, &mr); if (IS_ERR(seg)) return PTR_ERR(seg);
if (encode_rdma_segment(xdr, mr) < 0) return -EMSGSIZE;
if (wtype != rpcrdma_replych) { if (xdr_stream_encode_item_absent(xdr) < 0) return -EMSGSIZE; return0;
}
seg = req->rl_segments;
nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg); if (nsegs < 0) return nsegs;
if (xdr_stream_encode_item_present(xdr) < 0) return -EMSGSIZE;
segcount = xdr_reserve_space(xdr, sizeof(*segcount)); if (unlikely(!segcount)) return -EMSGSIZE; /* Actual value encoded below */
nchunks = 0; do {
seg = rpcrdma_mr_prepare(r_xprt, req, seg, nsegs, true, &mr); if (IS_ERR(seg)) return PTR_ERR(seg);
if (encode_rdma_segment(xdr, mr) < 0) return -EMSGSIZE;
/* The first two SGEs contain the transport header and *theinlinebuffer.Thesearealwaysleftmappedso *theycanbecheaplyre-used.
*/ for (sge = &sc->sc_sges[2]; sc->sc_unmap_count;
++sge, --sc->sc_unmap_count)
ib_dma_unmap_page(rdmab_device(rb), sge->addr, sge->length,
DMA_TO_DEVICE);
/* Copy the tail to the end of the head buffer.
*/ staticvoid rpcrdma_pullup_tail_iov(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req, struct xdr_buf *xdr)
{ unsignedchar *dst;
if (!rpcrdma_prepare_head_iov(r_xprt, req, xdr->head[0].iov_len)) returnfalse; if (xdr->page_len) if (!rpcrdma_prepare_pagelist(req, xdr)) returnfalse; if (tail->iov_len) if (!rpcrdma_prepare_tail_iov(req, xdr,
offset_in_page(tail->iov_base),
tail->iov_len)) returnfalse;
if (req->rl_sendctx->sc_unmap_count)
kref_get(&req->rl_kref); returntrue;
}
/* If there is a Read chunk, the page list is being handled *viaexplicitRDMA,andthusisskippedhere.
*/
/* Do not include the tail if it is only an XDR pad */ if (xdr->tail[0].iov_len > 3) { unsignedint page_base, len;
/* If the content in the page list is an odd length, *xdr_write_pages()addsapadatthebeginningof *thetailiovec.Forcethetail'snon-padcontentto *landatthenextXDRpositionintheSendmessage.
*/
page_base = offset_in_page(xdr->tail[0].iov_base);
len = xdr->tail[0].iov_len;
page_base += len & 3;
len -= len & 3; if (!rpcrdma_prepare_tail_iov(req, xdr, page_base, len)) returnfalse;
kref_get(&req->rl_kref);
}
ret = -EIO; switch (rtype) { case rpcrdma_noch_pullup: if (!rpcrdma_prepare_noch_pullup(r_xprt, req, xdr)) goto out_unmap; break; case rpcrdma_noch_mapped: if (!rpcrdma_prepare_noch_mapped(r_xprt, req, xdr)) goto out_unmap; break; case rpcrdma_readch: if (!rpcrdma_prepare_readch(r_xprt, req, xdr)) goto out_unmap; break; case rpcrdma_areadch: break; default: goto out_unmap;
}
/* Fixed header fields */
ret = -EMSGSIZE;
p = xdr_reserve_space(xdr, 4 * sizeof(*p)); if (!p) goto out_err;
*p++ = rqst->rq_xid;
*p++ = rpcrdma_version;
*p++ = r_xprt->rx_buf.rb_max_requests;
/* When the ULP employs a GSS flavor that guarantees integrity *orprivacy,directdataplacementofindividualdataitems *isnotallowed.
*/
ddp_allowed = !test_bit(RPCAUTH_AUTH_DATATOUCH,
&rqst->rq_cred->cr_auth->au_flags);
/** *rpcrdma_inline_fixup-Scatterinlinereceiveddataintorqst'siovecs *@rqst:controllingRPCrequest *@srcp:pointstoRPCmessagepayloadinreceivebuffer *@copy_len:remaininglengthofreceivebuffercontent *@pad:Writechunkpadbytesneeded(zeroforpureinline) * *Theupperlayerhassetthemaximumnumberofbytesitcan *receiveineachcomponentofrq_rcv_buf.Thesevaluesaresetin *thehead.iov_len,page_len,tail.iov_len,andbuflenfields. * *UnliketheTCPequivalent(xdr_partial_copy_from_skb),in *manycasesthisfunctionsimplyupdatesiov_basepointersin *rq_rcv_buftopointdirectlytothereceivedreplydata,to *avoidcopyingreplydata. * *Returnsthecountofbyteswhichhadtobememcopied.
*/ staticunsignedlong
rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
{ unsignedlong fixup_copy_count; int i, npages, curlen; char *destp; struct page **ppages; int page_base;
/* The head iovec is redirected to the RPC reply message *inthereceivebuffer,toavoidamemcopy.
*/
rqst->rq_rcv_buf.head[0].iov_base = srcp;
rqst->rq_private_buf.head[0].iov_base = srcp;
/* The contents of the receive buffer that follow *head.iov_lenbytesarecopiedintothepagelist.
*/
curlen = rqst->rq_rcv_buf.head[0].iov_len; if (curlen > copy_len)
curlen = copy_len;
srcp += curlen;
copy_len -= curlen;
ppages = rqst->rq_rcv_buf.pages +
(rqst->rq_rcv_buf.page_base >> PAGE_SHIFT);
page_base = offset_in_page(rqst->rq_rcv_buf.page_base);
fixup_copy_count = 0; if (copy_len && rqst->rq_rcv_buf.page_len) { int pagelist_len;
pagelist_len = rqst->rq_rcv_buf.page_len; if (pagelist_len > copy_len)
pagelist_len = copy_len;
npages = PAGE_ALIGN(page_base + pagelist_len) >> PAGE_SHIFT; for (i = 0; i < npages; i++) {
curlen = PAGE_SIZE - page_base; if (curlen > pagelist_len)
curlen = pagelist_len;
/* Implicit padding for the last segment in a Write *chunkisinsertedinlineatthefrontofthetail *iovec.Theupperlayerignoresthecontentof *thepad.Simplyensureinlinecontentinthetail *thatfollowstheWritechunkisproperlyaligned.
*/ if (pad)
srcp -= pad;
}
/* The tail iovec is redirected to the remaining data *inthereceivebuffer,toavoidamemcopy.
*/ if (copy_len || pad) {
rqst->rq_rcv_buf.tail[0].iov_base = srcp;
rqst->rq_private_buf.tail[0].iov_base = srcp;
}
if (fixup_copy_count)
trace_xprtrdma_fixup(rqst, fixup_copy_count); return fixup_copy_count;
}
/* Peek at stream contents without advancing. */
p = xdr_inline_decode(xdr, 0);
/* Chunk lists */ if (xdr_item_is_present(p++)) returnfalse; if (xdr_item_is_present(p++)) returnfalse; if (xdr_item_is_present(p++)) returnfalse;
/* RPC header */ if (*p++ != rep->rr_xid) returnfalse; if (*p != cpu_to_be32(RPC_CALL)) returnfalse;
/* No bc service. */ if (xprt->bc_serv == NULL) returnfalse;
/* Now that we are sure this is a backchannel call, *advancetotheRPCheader.
*/
p = xdr_inline_decode(xdr, 3 * sizeof(*p)); if (unlikely(!p)) returntrue;
p = xdr_inline_decode(xdr, sizeof(*p)); if (unlikely(!p)) return -EIO;
*length = 0;
segcount = be32_to_cpup(p); while (segcount--) { if (decode_rdma_segment(xdr, &seglength)) return -EIO;
*length += seglength;
}
return0;
}
/* In RPC-over-RDMA Version One replies, a Read list is never *expected.Thisdecoderisastubthatreturnsanerrorif *aReadlistispresent.
*/ staticint decode_read_list(struct xdr_stream *xdr)
{
__be32 *p;
p = xdr_inline_decode(xdr, sizeof(*p)); if (unlikely(!p)) return -EIO; if (unlikely(xdr_item_is_present(p))) return -EIO; return0;
}
/* Supports only one Write chunk in the Write list
*/ staticint decode_write_list(struct xdr_stream *xdr, u32 *length)
{
u32 chunklen; bool first;
__be32 *p;
*length = 0;
first = true; do {
p = xdr_inline_decode(xdr, sizeof(*p)); if (unlikely(!p)) return -EIO; if (xdr_item_is_absent(p)) break; if (!first) return -EIO;
if (decode_write_chunk(xdr, &chunklen)) return -EIO;
*length += chunklen;
first = false;
} while (true); return0;
}
/* Decode the chunk lists */ if (decode_read_list(xdr)) return -EIO; if (decode_write_list(xdr, &writelist)) return -EIO; if (decode_reply_chunk(xdr, &replychunk)) return -EIO;
/* RDMA_MSG sanity checks */ if (unlikely(replychunk)) return -EIO;
/* Build the RPC reply's Payload stream in rqst->rq_rcv_buf */
base = (char *)xdr_inline_decode(xdr, 0);
rpclen = xdr_stream_remaining(xdr);
r_xprt->rx_stats.fixup_copy_count +=
rpcrdma_inline_fixup(rqst, base, rpclen, writelist & 3);
/* Decode the chunk lists */ if (decode_read_list(xdr)) return -EIO; if (decode_write_list(xdr, &writelist)) return -EIO; if (decode_reply_chunk(xdr, &replychunk)) return -EIO;
/* RDMA_NOMSG sanity checks */ if (unlikely(writelist)) return -EIO; if (unlikely(!replychunk)) return -EIO;
/* Reply chunk buffer already is the reply vector */
r_xprt->rx_stats.total_rdma_reply += replychunk; return replychunk;
}
switch (rep->rr_proc) { case rdma_msg:
status = rpcrdma_decode_msg(r_xprt, rep, rqst); break; case rdma_nomsg:
status = rpcrdma_decode_nomsg(r_xprt, rep); break; case rdma_error:
status = rpcrdma_decode_error(r_xprt, rep, rqst); break; default:
status = -EIO;
} if (status < 0) goto out_badheader;
/* Any data means we had a useful conversation, so *thenwedon'tneedtodelaythenextreconnect.
*/ if (xprt->reestablish_timeout)
xprt->reestablish_timeout = 0;
if (rep->rr_vers != rpcrdma_version) goto out_badversion;
if (rpcrdma_is_bcall(r_xprt, rep)) return;
/* Match incoming rpcrdma_rep to an rpcrdma_req to *getcontextforhandlinganyincomingchunks.
*/
spin_lock(&xprt->queue_lock);
rqst = xprt_lookup_rqst(xprt, rep->rr_xid); if (!rqst) goto out_norqst;
xprt_pin_rqst(rqst);
spin_unlock(&xprt->queue_lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.