Hi all, Today's linux-next merge of the nfs-anna tree got a conflict in: net/sunrpc/xprtrdma/rpc_rdma.c between commit: a0db57fee35ec ("xprtrdma: Fix Write chunk payload corruption on a short reply header") from the nfs tree and commit: 9ee534a759123 ("xprtrdma: trim head iovec when the payload arrives via a Write chunk") from the nfs-anna tree. I fixed it up (see below) and can carry the fix as necessary. This is now fixed as far as linux-next is concerned, but any non trivial conflicts should be mentioned to your upstream maintainer when your tree is submitted for merging. You may also want to consider cooperating with the maintainer of the conflicting tree to minimise any particularly complex conflicts. This one definitely needs double checking. diff --combined net/sunrpc/xprtrdma/rpc_rdma.c index ba8bdca8a49fb,7e5713367291e..0000000000000 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@@ -984,12 -984,16 +984,16 @@@ void rpcrdma_reset_cwnd(struct rpcrdma_ * @rqst: controlling RPC request * @srcp: points to RPC message payload in receive buffer * @copy_len: remaining length of receive buffer content - * @pad: Write chunk pad bytes needed (zero for pure inline) + * @writelist: bytes conveyed by the Write chunk (zero for pure inline) * * The upper layer has set the maximum number of bytes it can * receive in each component of rq_rcv_buf. These values are set in * the head.iov_len, page_len, tail.iov_len, and buflen fields. * + * For READ replies with a Write chunk, the payload is already in + * the page list. An overestimated head length and buflen can be + * reduced without moving reply data. + * * Unlike the TCP equivalent (xdr_partial_copy_from_skb), in * many cases this function simply updates iov_base pointers in * rq_rcv_buf to point directly to the received reply data, to @@@ -998,13 -1002,16 +1002,16 @@@ * Returns the count of bytes which had to be memcopied. */ static unsigned long - rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) + rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, + u32 writelist) { unsigned long fixup_copy_count; int i, npages, curlen; char *destp; struct page **ppages; int page_base; + int pad = writelist & 3; + unsigned int delta; /* The head iovec is redirected to the RPC reply message * in the receive buffer, to avoid a memcopy. @@@ -1016,8 -1023,20 +1023,20 @@@ * head.iov_len bytes are copied into the page list. */ curlen = rqst->rq_rcv_buf.head[0].iov_len; - if (curlen > copy_len) + if (curlen > copy_len) { + /* These READ replies have no inline fields after the payload. + * Trim the head without moving the directly-placed data. + */ + if (writelist) { + delta = curlen - copy_len; + + rqst->rq_rcv_buf.head[0].iov_len = copy_len; + rqst->rq_private_buf.head[0].iov_len = copy_len; + rqst->rq_rcv_buf.buflen -= delta; + rqst->rq_private_buf.buflen -= delta; + } curlen = copy_len; + } srcp += curlen; copy_len -= curlen; @@@ -1243,19 -1262,9 +1262,19 @@@ rpcrdma_decode_msg(struct rpcrdma_xprt /* Build the RPC reply's Payload stream in rqst->rq_rcv_buf */ base = (char *)xdr_inline_decode(xdr, 0); - rpclen = xdr_stream_remaining(xdr); + rpclen = rep->rr_hdrbuf.len - xdr_stream_pos(xdr); + if (writelist) + rpclen &= ~3; + if (unlikely(!rpclen)) + return -EIO; + if (writelist && rpclen < rqst->rq_rcv_buf.head[0].iov_len) { + rqst->rq_rcv_buf.head[0].iov_len = rpclen; + rqst->rq_private_buf.head[0].iov_len = rpclen; + } + r_xprt->rx_stats.fixup_copy_count += - rpcrdma_inline_fixup(rqst, base, rpclen, writelist); + rpcrdma_inline_fixup(rqst, base, rpclen, + xdr_pad_size(writelist)); r_xprt->rx_stats.total_rdma_reply += writelist; return rpclen + xdr_align_size(writelist);