Skip to content

Commit d6764bb

Browse files
chuckleveramschuma-ntap
authored andcommitted
xprtrdma: Refactor rpcrdma_prepare_msg_sges()
Refactor: Replace spaghetti with code that makes it plain what needs to be done for each rtype. This makes it easier to add features and optimizations. Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent dc15c3d commit d6764bb

File tree

1 file changed

+146
-117
lines changed

1 file changed

+146
-117
lines changed

net/sunrpc/xprtrdma/rpc_rdma.c

Lines changed: 146 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -589,148 +589,162 @@ static bool rpcrdma_prepare_hdr_sge(struct rpcrdma_xprt *r_xprt,
589589
{
590590
struct rpcrdma_sendctx *sc = req->rl_sendctx;
591591
struct rpcrdma_regbuf *rb = req->rl_rdmabuf;
592-
struct ib_sge *sge = sc->sc_sges;
592+
struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
593593

594594
if (!rpcrdma_regbuf_dma_map(r_xprt, rb))
595-
goto out_regbuf;
595+
return false;
596596
sge->addr = rdmab_addr(rb);
597597
sge->length = len;
598598
sge->lkey = rdmab_lkey(rb);
599599

600600
ib_dma_sync_single_for_device(rdmab_device(rb), sge->addr, sge->length,
601601
DMA_TO_DEVICE);
602-
req->rl_wr.num_sge++;
603602
return true;
604-
605-
out_regbuf:
606-
pr_err("rpcrdma: failed to DMA map a Send buffer\n");
607-
return false;
608603
}
609604

610-
/* Prepare the Send SGEs. The head and tail iovec, and each entry
611-
* in the page list, gets its own SGE.
605+
/* The head iovec is straightforward, as it is usually already
606+
* DMA-mapped. Sync the content that has changed.
612607
*/
613-
static bool rpcrdma_prepare_msg_sges(struct rpcrdma_xprt *r_xprt,
614-
struct rpcrdma_req *req,
615-
struct xdr_buf *xdr,
616-
enum rpcrdma_chunktype rtype)
608+
static bool rpcrdma_prepare_head_iov(struct rpcrdma_xprt *r_xprt,
609+
struct rpcrdma_req *req, unsigned int len)
617610
{
618611
struct rpcrdma_sendctx *sc = req->rl_sendctx;
619-
unsigned int sge_no, page_base, len, remaining;
612+
struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
620613
struct rpcrdma_regbuf *rb = req->rl_sendbuf;
621-
struct ib_sge *sge = sc->sc_sges;
622-
struct page *page, **ppages;
623614

624-
/* The head iovec is straightforward, as it is already
625-
* DMA-mapped. Sync the content that has changed.
626-
*/
627615
if (!rpcrdma_regbuf_dma_map(r_xprt, rb))
628-
goto out_regbuf;
629-
sge_no = 1;
630-
sge[sge_no].addr = rdmab_addr(rb);
631-
sge[sge_no].length = xdr->head[0].iov_len;
632-
sge[sge_no].lkey = rdmab_lkey(rb);
633-
ib_dma_sync_single_for_device(rdmab_device(rb), sge[sge_no].addr,
634-
sge[sge_no].length, DMA_TO_DEVICE);
635-
636-
/* If there is a Read chunk, the page list is being handled
637-
* via explicit RDMA, and thus is skipped here. However, the
638-
* tail iovec may include an XDR pad for the page list, as
639-
* well as additional content, and may not reside in the
640-
* same page as the head iovec.
641-
*/
642-
if (rtype == rpcrdma_readch) {
643-
len = xdr->tail[0].iov_len;
616+
return false;
644617

645-
/* Do not include the tail if it is only an XDR pad */
646-
if (len < 4)
647-
goto out;
618+
sge->addr = rdmab_addr(rb);
619+
sge->length = len;
620+
sge->lkey = rdmab_lkey(rb);
648621

649-
page = virt_to_page(xdr->tail[0].iov_base);
650-
page_base = offset_in_page(xdr->tail[0].iov_base);
622+
ib_dma_sync_single_for_device(rdmab_device(rb), sge->addr, sge->length,
623+
DMA_TO_DEVICE);
624+
return true;
625+
}
651626

652-
/* If the content in the page list is an odd length,
653-
* xdr_write_pages() has added a pad at the beginning
654-
* of the tail iovec. Force the tail's non-pad content
655-
* to land at the next XDR position in the Send message.
656-
*/
657-
page_base += len & 3;
658-
len -= len & 3;
659-
goto map_tail;
660-
}
627+
/* If there is a page list present, DMA map and prepare an
628+
* SGE for each page to be sent.
629+
*/
630+
static bool rpcrdma_prepare_pagelist(struct rpcrdma_req *req,
631+
struct xdr_buf *xdr)
632+
{
633+
struct rpcrdma_sendctx *sc = req->rl_sendctx;
634+
struct rpcrdma_regbuf *rb = req->rl_sendbuf;
635+
unsigned int page_base, len, remaining;
636+
struct page **ppages;
637+
struct ib_sge *sge;
661638

662-
/* If there is a page list present, temporarily DMA map
663-
* and prepare an SGE for each page to be sent.
664-
*/
665-
if (xdr->page_len) {
666-
ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT);
667-
page_base = offset_in_page(xdr->page_base);
668-
remaining = xdr->page_len;
669-
while (remaining) {
670-
sge_no++;
671-
if (sge_no > RPCRDMA_MAX_SEND_SGES - 2)
672-
goto out_mapping_overflow;
673-
674-
len = min_t(u32, PAGE_SIZE - page_base, remaining);
675-
sge[sge_no].addr =
676-
ib_dma_map_page(rdmab_device(rb), *ppages,
677-
page_base, len, DMA_TO_DEVICE);
678-
if (ib_dma_mapping_error(rdmab_device(rb),
679-
sge[sge_no].addr))
680-
goto out_mapping_err;
681-
sge[sge_no].length = len;
682-
sge[sge_no].lkey = rdmab_lkey(rb);
683-
684-
sc->sc_unmap_count++;
685-
ppages++;
686-
remaining -= len;
687-
page_base = 0;
688-
}
689-
}
639+
ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT);
640+
page_base = offset_in_page(xdr->page_base);
641+
remaining = xdr->page_len;
642+
while (remaining) {
643+
sge = &sc->sc_sges[req->rl_wr.num_sge++];
644+
len = min_t(unsigned int, PAGE_SIZE - page_base, remaining);
645+
sge->addr = ib_dma_map_page(rdmab_device(rb), *ppages,
646+
page_base, len, DMA_TO_DEVICE);
647+
if (ib_dma_mapping_error(rdmab_device(rb), sge->addr))
648+
goto out_mapping_err;
690649

691-
/* The tail iovec is not always constructed in the same
692-
* page where the head iovec resides (see, for example,
693-
* gss_wrap_req_priv). To neatly accommodate that case,
694-
* DMA map it separately.
695-
*/
696-
if (xdr->tail[0].iov_len) {
697-
page = virt_to_page(xdr->tail[0].iov_base);
698-
page_base = offset_in_page(xdr->tail[0].iov_base);
699-
len = xdr->tail[0].iov_len;
650+
sge->length = len;
651+
sge->lkey = rdmab_lkey(rb);
700652

701-
map_tail:
702-
sge_no++;
703-
sge[sge_no].addr =
704-
ib_dma_map_page(rdmab_device(rb), page, page_base, len,
705-
DMA_TO_DEVICE);
706-
if (ib_dma_mapping_error(rdmab_device(rb), sge[sge_no].addr))
707-
goto out_mapping_err;
708-
sge[sge_no].length = len;
709-
sge[sge_no].lkey = rdmab_lkey(rb);
710653
sc->sc_unmap_count++;
654+
ppages++;
655+
remaining -= len;
656+
page_base = 0;
711657
}
712658

713-
out:
714-
req->rl_wr.num_sge += sge_no;
715-
if (sc->sc_unmap_count)
716-
kref_get(&req->rl_kref);
717659
return true;
718660

719-
out_regbuf:
720-
pr_err("rpcrdma: failed to DMA map a Send buffer\n");
661+
out_mapping_err:
662+
trace_xprtrdma_dma_maperr(sge->addr);
721663
return false;
664+
}
722665

723-
out_mapping_overflow:
724-
rpcrdma_sendctx_unmap(sc);
725-
pr_err("rpcrdma: too many Send SGEs (%u)\n", sge_no);
726-
return false;
666+
/* The tail iovec may include an XDR pad for the page list,
667+
* as well as additional content, and may not reside in the
668+
* same page as the head iovec.
669+
*/
670+
static bool rpcrdma_prepare_tail_iov(struct rpcrdma_req *req,
671+
struct xdr_buf *xdr,
672+
unsigned int page_base, unsigned int len)
673+
{
674+
struct rpcrdma_sendctx *sc = req->rl_sendctx;
675+
struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
676+
struct rpcrdma_regbuf *rb = req->rl_sendbuf;
677+
struct page *page = virt_to_page(xdr->tail[0].iov_base);
678+
679+
sge->addr = ib_dma_map_page(rdmab_device(rb), page, page_base, len,
680+
DMA_TO_DEVICE);
681+
if (ib_dma_mapping_error(rdmab_device(rb), sge->addr))
682+
goto out_mapping_err;
683+
684+
sge->length = len;
685+
sge->lkey = rdmab_lkey(rb);
686+
++sc->sc_unmap_count;
687+
return true;
727688

728689
out_mapping_err:
729-
rpcrdma_sendctx_unmap(sc);
730-
trace_xprtrdma_dma_maperr(sge[sge_no].addr);
690+
trace_xprtrdma_dma_maperr(sge->addr);
731691
return false;
732692
}
733693

694+
static bool rpcrdma_prepare_noch_mapped(struct rpcrdma_xprt *r_xprt,
695+
struct rpcrdma_req *req,
696+
struct xdr_buf *xdr)
697+
{
698+
struct kvec *tail = &xdr->tail[0];
699+
700+
if (!rpcrdma_prepare_head_iov(r_xprt, req, xdr->head[0].iov_len))
701+
return false;
702+
if (xdr->page_len)
703+
if (!rpcrdma_prepare_pagelist(req, xdr))
704+
return false;
705+
if (tail->iov_len)
706+
if (!rpcrdma_prepare_tail_iov(req, xdr,
707+
offset_in_page(tail->iov_base),
708+
tail->iov_len))
709+
return false;
710+
711+
if (req->rl_sendctx->sc_unmap_count)
712+
kref_get(&req->rl_kref);
713+
return true;
714+
}
715+
716+
static bool rpcrdma_prepare_readch(struct rpcrdma_xprt *r_xprt,
717+
struct rpcrdma_req *req,
718+
struct xdr_buf *xdr)
719+
{
720+
if (!rpcrdma_prepare_head_iov(r_xprt, req, xdr->head[0].iov_len))
721+
return false;
722+
723+
/* If there is a Read chunk, the page list is being handled
724+
* via explicit RDMA, and thus is skipped here.
725+
*/
726+
727+
/* Do not include the tail if it is only an XDR pad */
728+
if (xdr->tail[0].iov_len > 3) {
729+
unsigned int page_base, len;
730+
731+
/* If the content in the page list is an odd length,
732+
* xdr_write_pages() adds a pad at the beginning of
733+
* the tail iovec. Force the tail's non-pad content to
734+
* land at the next XDR position in the Send message.
735+
*/
736+
page_base = offset_in_page(xdr->tail[0].iov_base);
737+
len = xdr->tail[0].iov_len;
738+
page_base += len & 3;
739+
len -= len & 3;
740+
if (!rpcrdma_prepare_tail_iov(req, xdr, page_base, len))
741+
return false;
742+
kref_get(&req->rl_kref);
743+
}
744+
745+
return true;
746+
}
747+
734748
/**
735749
* rpcrdma_prepare_send_sges - Construct SGEs for a Send WR
736750
* @r_xprt: controlling transport
@@ -741,17 +755,17 @@ static bool rpcrdma_prepare_msg_sges(struct rpcrdma_xprt *r_xprt,
741755
*
742756
* Returns 0 on success; otherwise a negative errno is returned.
743757
*/
744-
int
745-
rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
746-
struct rpcrdma_req *req, u32 hdrlen,
747-
struct xdr_buf *xdr, enum rpcrdma_chunktype rtype)
758+
inline int rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
759+
struct rpcrdma_req *req, u32 hdrlen,
760+
struct xdr_buf *xdr,
761+
enum rpcrdma_chunktype rtype)
748762
{
749763
int ret;
750764

751765
ret = -EAGAIN;
752766
req->rl_sendctx = rpcrdma_sendctx_get_locked(r_xprt);
753767
if (!req->rl_sendctx)
754-
goto err;
768+
goto out_nosc;
755769
req->rl_sendctx->sc_unmap_count = 0;
756770
req->rl_sendctx->sc_req = req;
757771
kref_init(&req->rl_kref);
@@ -762,13 +776,28 @@ rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
762776

763777
ret = -EIO;
764778
if (!rpcrdma_prepare_hdr_sge(r_xprt, req, hdrlen))
765-
goto err;
766-
if (rtype != rpcrdma_areadch)
767-
if (!rpcrdma_prepare_msg_sges(r_xprt, req, xdr, rtype))
768-
goto err;
779+
goto out_unmap;
780+
781+
switch (rtype) {
782+
case rpcrdma_noch:
783+
if (!rpcrdma_prepare_noch_mapped(r_xprt, req, xdr))
784+
goto out_unmap;
785+
break;
786+
case rpcrdma_readch:
787+
if (!rpcrdma_prepare_readch(r_xprt, req, xdr))
788+
goto out_unmap;
789+
break;
790+
case rpcrdma_areadch:
791+
break;
792+
default:
793+
goto out_unmap;
794+
}
795+
769796
return 0;
770797

771-
err:
798+
out_unmap:
799+
rpcrdma_sendctx_unmap(req->rl_sendctx);
800+
out_nosc:
772801
trace_xprtrdma_prepsend_failed(&req->rl_slot, ret);
773802
return ret;
774803
}

0 commit comments

Comments
 (0)