From nobody Tue Sep 01 14:06:47 2026 X-Original-To: dev-commits-src-main@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 4hZ72c34Rhz6qw9Q for ; Tue, 01 Sep 2026 14:06:48 +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 4hZ72b5zDQz3st1 for ; Tue, 01 Sep 2026 14:06:47 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788271607; 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=AatimRO4GrxcyGcw3bPDZh15ykoI8dfAuX0Cqkmqf3vI0FZ1HQpQqJsQ+nA0mvP4YIwNJD jbwZs1qv5l86V+8//21seYrot1d/47u3iRbFhwS342vEHkvmECz5jC373RTFOMb6GmoAkx FgV9hvoKdEa0xEOLhkPe/EcQs3rtrO2h/FXw1X1N1AfPLFx4DHo0iAxNQR2IYCkpHd/nhf BgcyyWZjpgokQFdbNedOclr320l0NjaJO596re2IHraFVna1DPQ8rOjyAYsdXYCNnXGI8Y 5BHLy6+WpNMAUDLVcJujQnZwMjP7UY+nZYRO/EQByr7U4gLjquPKf8VaEWBwbQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788271607; a=rsa-sha256; cv=none; b=frRL9Me/NaQ+jUeWn9ZSx4ZyKHl9o/WYzqQ4yeGqeznEFNNBMlUZMEyaJ81mzCuqk9TrH2 mglCcjTxyzs7y8Y1AC5hxY0a9fZFTgUK3eRp1n8mDjm8NCSyaK3v2H22PdyW80pcx+fUCG FxYgF/+nEkhn8Df3HkEFiQcvSq8RVT4jv4+48S0lzNUUIyBesutLOEES20f3cIx7tSKXhw NIA68MHJ9mhSWLtk0Z7qwNm2nXEe+yX3VZcrIImD1WE/ycTA+9aim8iZxQ1HcTfqNVmB4/ mbmwSK57poU9gc6Gl1rHmr2mEUUdjbJ/LfCzTTkmxAdzgme9MAnW6Ph6RN9Ohg== 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=1788271607; 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=VVGtkfEwpgANvKo2yK2bT14Sl56f1KFz9VEAbI8IS8rfWxjawzfhbErDhnsZj6UiIta8m1 pNb3NtXLMt1jcXAohE0lVXcH4AwWZiPt6Q5hgADgSs/ZrJ1YH5sxqoaUupIYmFHxYfXroJ X78vyQvKACW4jCwnC23WsWq6xPV0UCFWn21PZEvrTGo5Z7Hjl5DuoCzsYyC5W4jordHV2x SJbgSoiPy9gZU/Nk5iJvl+SAPdE7qWhXwmsZKR4H6XbEeAiH+SKWnUnhsLmzVc43mkgE7o QnU35aoRITBUN/ue1uaDzNBIdF1Oekgj+K4S/Yxs5bhm0jvX9ciWhM26UceTsg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hZ72b4Wwpz11Yf for ; Tue, 01 Sep 2026 14:06:47 +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 the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@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); }