From nobody Tue Sep 01 14:06:47 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hZ72h6MCPz6qw9R for ; Tue, 01 Sep 2026 14:06:52 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hZ72h5Q1kz3tBf for ; Tue, 01 Sep 2026 14:06:52 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788271612; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nZaAY7yLrj5yenMpDVPkTk4Q6Oa8QPPaJO0npHIiRno=; b=caMR5P9+B+jvymmqg5SWcwL+pRJ3fWa97hS4bvrfCjLgLCXtoePvo14DSj9nb60/496ubY pU2/dHDCmrzSxL/qmU6bTralCPfQ468k3FcHmFFHb/tVreXz4vWvMym6vg5QRPtU832maE lNPVWVQxsjqxm6C6gEREXSQao1om1L0J/SkNmRmr7eZx3WIu2z1keYUzZOpuG/hnhcUT+y znObe9MOF93WcNLl5pD6iu1p21tMvuZcS0ccYBSpXuxMgc8x5ck8N697owrruPpu/Bmb1R L/7L5SroX05osPxIGIR36tU5QVErMeq+PTRQCbY0FsCJJ1XsTpw1CJywJrdPlQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788271612; a=rsa-sha256; cv=none; b=RL7T6OTxSQcd3Tu3D2TSaCj8ho2Kdjt+6pC9THn1+SW5X+y4csxgybhABBVo49W5Rhac7v aKmF3COKf0JWxYUxQPbdloOd9yKOQHrgafdAbw7db1tprfzWDgRXBGK1b7mrAghoY2eSsH DDeml5I5ukUAYyo6BE90XEfpdEAjSq/abbWhd46b9Oqa5T1HbuSVS2JdIEhAC8Hdi35AQT hrYbP+BMEz5K4WzX11+3Enty28dSWSBy90ZQiW/bIIFkB/ppxyHq2uUp3X3m5ddHRcZDk2 8hGnvgJVWIkB8YDlfjUGmWgzMGkDVEsxWs11mb/sCfQR7RuKln1Au12G/NL6+Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788271612; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nZaAY7yLrj5yenMpDVPkTk4Q6Oa8QPPaJO0npHIiRno=; b=ty+cELfil0zv5LI1UoXA1IVzBJcv+wwa6/3+dVGzThyc1ObpkGbpd+8cXNOEb7TL6X/h20 bQ+QoIak0hngyHzgqCW/jfn20iIO2G5tSUHuW2O778m3pN4ujrBd8j6rA+DTEvAlrBbFSF k5IhAe1hVlNg3PzNoACV8WLXR7HPyW+xqlAiNaDo4Gd0tiQeC4ttzWPyTTAl6OiIgOr4xm /cvTos4v1AXrP6fBgq15NVS44qOffyWsrsqi6u8TfhD9X3CVa1qPcaRxZ+jL+4nfXhTjmC tUn6mba47SBVzWxUQR/9s2MxwPCRb4/RzUMwxKjtRLp6GSxGsnruxw3mjaU0sw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hZ72h4Jhsz11kl for ; Tue, 01 Sep 2026 14:06:52 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1d1ab by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 01 Sep 2026 14:06:47 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: f41d83578e8e - main - nfsclient: Fix problems with the NFS over RDMA glue List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: f41d83578e8eb1efced76704f00bcf6b201c3821 Auto-Submitted: auto-generated Date: Tue, 01 Sep 2026 14:06:47 +0000 Message-Id: <6a96dbf7.1d1ab.7f67442@gitrepo.freebsd.org> The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=f41d83578e8eb1efced76704f00bcf6b201c3821 commit f41d83578e8eb1efced76704f00bcf6b201c3821 Author: Rick Macklem AuthorDate: 2026-09-01 13:53:34 +0000 Commit: Rick Macklem CommitDate: 2026-09-01 14:05:20 +0000 nfsclient: Fix problems with the NFS over RDMA glue There were a couple of problems detected w.r.t. the "glue" for the nfsclrdma.ko module. - When the NFS server has a small reply for a read, it can choose to not use the reduction chunk (separate memory area for the read data). I did not realize this was the case. - There was a bug in rpc_copy_uio_pages() function that caused intermittent crashes in memcpy(). This patch fixes the above cases. It uses M_PROTO6 to mark that an RPC reply has used a reduction chunk, so that read can handle it correctly. Read also now provides a reduction chunk for all read sizes, since the worst case for the rest of the read RPC reply is close to the 1024 byte limit. (NFSv4 uses strings instead of uid/gid in the attributes and these name strings can be rather large.) I wanted to get the "glue" into main so that others could test the module more easily. Avaliability of the module will be announced on freebsd-current@ soon. It should not affect non-RDMA operation. I've specified a long MFC, since the module still requires extensive testing and, hopefully, a review. MFC after: 3 months Fixes: 884ee8d6c9b4 ("nfscl: Add some glue for client side NFS over RDMA") --- sys/fs/nfsclient/nfs_clrpcops.c | 58 ++++++++++++++++++++++------ sys/rpc/rpc_generic.c | 84 ++++++++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 47 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 6e84567649d7..d8e1f17b66ae 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -1822,7 +1822,7 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { - u_int32_t *tl; + uint32_t *tl, mbflag; int error = 0, len, retlen, tsiz, eof = 0; struct nfsrv_descript nfsd; struct mbuf *mr; @@ -1830,13 +1830,23 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, struct nfsrv_descript *nd = &nfsd; int rsize; off_t tmp_off; - bool did_rdma; + bool did_rdma, reduced; *attrflagp = 0; tsiz = uiop->uio_resid; did_rdma = false; - if (NFSHASRDMA(nmp) && tsiz > RPCRDMA_MAX_SMALL_MSG / 2) - did_rdma = true; + mbflag = 0; + if (NFSHASRDMA(nmp) && tsiz > 0) { + /* Assume the rest of the RPC without data is <= 1024 bytes. */ + if ((uiop->uio_offset & PAGE_MASK) == 0) + did_rdma = true; + else if (tsiz <= PAGE_SIZE - 1024) + mbflag = M_PROTO7; + else if (tsiz <= NFS_DIRBLKSIZ + PAGE_SIZE - 1024) + mbflag = M_PROTO8; + else + mbflag = M_PROTO9; + } tmp_off = uiop->uio_offset + tsiz; NFSLOCKMNT(nmp); if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { @@ -1846,10 +1856,12 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, rsize = nmp->nm_rsize; NFSUNLOCKMNT(nmp); nd->nd_mrep = NULL; + mr = NULL; while (tsiz > 0) { *attrflagp = 0; len = (tsiz > rsize) ? rsize : tsiz; NFSCL_REQSTART(nd, NFSPROC_READ, vp, cred); + nd->nd_mreq->m_flags |= mbflag; if (nd->nd_flag & ND_NFSV4) nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); @@ -1870,8 +1882,14 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, * (See the comment in nfsrpc_writerpc() for more info.) */ error = nfscl_request(nd, vp, p, cred); - if (error) + if (error) { + if (mr != NULL) + rpc_free_rdma_reduction(mr); return (error); + } + reduced = false; + if ((nd->nd_mrep->m_flags & M_PROTO6) != 0) + reduced = true; if (nd->nd_flag & ND_NFSV3) { error = nfscl_postop_attr(nd, nap, attrflagp); } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { @@ -1892,11 +1910,16 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, eof = fxdr_unsigned(int, *tl); } NFSM_STRSIZ(retlen, len); - if (!did_rdma) { - error = nfsm_mbufuio(nd, uiop, retlen); - } else { - error = rpc_copy_uio_pages(mr, uiop, retlen, true); + if (retlen > 0) { + if (!did_rdma || !reduced) + error = nfsm_mbufuio(nd, uiop, retlen); + else + error = rpc_copy_uio_pages(mr, uiop, retlen, + true); + } + if (mr != NULL) { rpc_free_rdma_reduction(mr); + mr = NULL; } if (error) goto nfsmout; @@ -1911,6 +1934,8 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, } return (0); nfsmout: + if (mr != NULL) + rpc_free_rdma_reduction(mr); if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); return (error); @@ -2029,7 +2054,7 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, *attrflagp = 0; tsiz = uiop->uio_resid; did_rdma = false; - if (NFSHASRDMA(nmp) && tsiz > RPCRDMA_MAX_SMALL_MSG / 2) + if (NFSHASRDMA(nmp) && (uiop->uio_offset & PAGE_MASK) == 0) did_rdma = true; tmp_off = uiop->uio_offset + tsiz; NFSLOCKMNT(nmp); @@ -2045,6 +2070,7 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK); nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ + mr = NULL; while (tsiz > 0) { *attrflagp = 0; len = (tsiz > wsize) ? wsize : tsiz; @@ -2099,8 +2125,10 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, rlen = m_length(nd->nd_mreq, NULL); mr = nfsm_build_rdma_reduction(nd, len, rlen, false); error = rpc_copy_uio_pages(mr, uiop, len, false); - if (error) + if (error != 0) { rpc_free_rdma_reduction(mr); + mr = NULL; + } } else { error = nfsm_uiombuf(nd, uiop, len); } @@ -2137,11 +2165,17 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, } error = nfscl_request(nd, vp, p, cred); if (error) { + if (mr != NULL) + rpc_free_rdma_reduction(mr); free(nd, M_TEMP); return (error); } - if (did_rdma && !NFSHASNOWRITEREDUCE(nmp)) + if (did_rdma && !NFSHASNOWRITEREDUCE(nmp)) { + KASSERT(mr != NULL, ("nfsrpc_writerpc: Null mr")); + rpc_free_rdma_reduction(mr); + mr = NULL; + } if (nd->nd_repstat) { /* * In case the rpc gets retried, roll diff --git a/sys/rpc/rpc_generic.c b/sys/rpc/rpc_generic.c index 585d89a6931c..7172a19164c2 100644 --- a/sys/rpc/rpc_generic.c +++ b/sys/rpc/rpc_generic.c @@ -985,59 +985,73 @@ rpc_free_rdma_reduction(struct mbuf *mr) * Copy data between anonymous pages and uiop. */ int -rpc_copy_uio_pages(struct mbuf *mr, struct uio *uiop, int len, bool from_pages) +rpc_copy_uio_pages(struct mbuf *mr, struct uio *uiop, int siz, bool from_pages) { struct rpcrdma_reduce_pg *rb; - struct iovec *iov; - int cplen, error, lastlen, i, xfer; - char *cp; + char *cp, *uiocp; + int error, left, len, i, uiosiz, xfer; rb = mtod(mr, struct rpcrdma_reduce_pg *); - iov = uiop->uio_iov; - lastlen = rb->len % PAGE_SIZE; - if (lastlen == 0) - lastlen = PAGE_SIZE; - for (i = 0; i < rb->npg && len > 0; i++) { - xfer = (i == rb->npg - 1) ? lastlen : PAGE_SIZE; - xfer = MIN(xfer, len); - cp = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(rb->pg[i])); - while (xfer > 0) { - while (iov->iov_len == 0) { - if (uiop->uio_iovcnt > 0) { - iov++; - uiop->uio_iovcnt--; - } else { - return (ENOMEM); - } + if (siz > rb->len) + return (EBADRPC); + i = 0; + cp = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(rb->pg[i])); + len = PAGE_SIZE; + if (i == rb->npg - 1 && siz < PAGE_SIZE) + len = siz; + while (siz > 0) { + if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) + return (EBADRPC); + left = uiop->uio_iov->iov_len; + uiocp = uiop->uio_iov->iov_base; + if (left > siz) + left = siz; + uiosiz = left; + while (left > 0) { + if (len == 0) { + if (i == rb->npg - 1) + return (EBADRPC); + i++; + cp = PHYS_TO_DMAP( + VM_PAGE_TO_PHYS(rb->pg[i])); + len = PAGE_SIZE; + if (i == rb->npg - 1 && siz < PAGE_SIZE) + len = siz; } - cplen = MIN(iov->iov_len, xfer); + xfer = (left > len) ? len : left; if (from_pages) { if (uiop->uio_segflg == UIO_SYSSPACE) { - memcpy(iov->iov_base, cp, cplen); + memcpy(uiocp, cp, xfer); } else { - error = copyout(cp, iov->iov_base, - cplen); + error = copyout(cp, uiocp, xfer); if (error != 0) - return (error); + return (EBADRPC); } } else { if (uiop->uio_segflg == UIO_SYSSPACE) { - memcpy(cp, iov->iov_base, cplen); + memcpy(cp, uiocp, xfer); } else { - error = copyin(iov->iov_base, cp, - cplen); + error = copyout(uiocp, cp, xfer); if (error != 0) - return (error); + return (EBADRPC); } } - iov->iov_len -= cplen; - iov->iov_base = (char *)iov->iov_base + cplen; - uiop->uio_offset += cplen; - uiop->uio_resid -= cplen; - xfer -= cplen; - cp += cplen; + left -= xfer; len -= xfer; + cp += xfer; + uiocp += xfer; + uiop->uio_offset += xfer; + uiop->uio_resid -= xfer; + } + if (uiop->uio_iov->iov_len <= siz) { + uiop->uio_iovcnt--; + uiop->uio_iov++; + } else { + uiop->uio_iov->iov_base = (void *) + ((char *)uiop->uio_iov->iov_base + uiosiz); + uiop->uio_iov->iov_len -= uiosiz; } + siz -= uiosiz; } return (0); }