Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jul 2020 02:19:01 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r363470 - in projects/nfs-over-tls/sys/fs: nfs nfsclient
Message-ID:  <202007240219.06O2J14h056914@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Fri Jul 24 02:19:00 2020
New Revision: 363470
URL: https://svnweb.freebsd.org/changeset/base/363470

Log:
  Update nfsm_uiombuflist() and nfscl_dofflayoutio() so that ext_pgs mbufs
  can be used.
  
  The use of ext_pgs mbufs is not yet enabled, since it requires changes
  to ktls_encrypt() so that the encrypted pages are not in the same mbuf list.

Modified:
  projects/nfs-over-tls/sys/fs/nfs/nfs_var.h
  projects/nfs-over-tls/sys/fs/nfsclient/nfs_clcomsubs.c
  projects/nfs-over-tls/sys/fs/nfsclient/nfs_clrpcops.c

Modified: projects/nfs-over-tls/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfs/nfs_var.h	Fri Jul 24 01:25:57 2020	(r363469)
+++ projects/nfs-over-tls/sys/fs/nfs/nfs_var.h	Fri Jul 24 02:19:00 2020	(r363470)
@@ -363,7 +363,7 @@ void nfsm_set(struct nfsrv_descript *, u_int);
 
 /* nfs_clcomsubs.c */
 void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
-struct mbuf *nfsm_uiombuflist(struct uio *, int, struct mbuf **, char **);
+struct mbuf *nfsm_uiombuflist(struct uio *, int, u_int);
 nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int);
 u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *);
 int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **);

Modified: projects/nfs-over-tls/sys/fs/nfsclient/nfs_clcomsubs.c
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfsclient/nfs_clcomsubs.c	Fri Jul 24 01:25:57 2020	(r363469)
+++ projects/nfs-over-tls/sys/fs/nfsclient/nfs_clcomsubs.c	Fri Jul 24 02:19:00 2020	(r363470)
@@ -160,26 +160,35 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *ui
  * NOTE: can ony handle iovcnt == 1
  */
 struct mbuf *
-nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
+nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
 {
 	char *uiocp;
 	struct mbuf *mp, *mp2, *firstmp;
-	int xfer, left, mlen;
+	int extpg, extpgsiz = 0, i, left, mlen, rem, xfer;
 	int uiosiz, clflg;
-	char *tcp;
+	char *mcp, *tcp;
 
 	KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
 
-	if (siz > ncl_mbuf_mlen)	/* or should it >= MCLBYTES ?? */
-		clflg = 1;
-	else
-		clflg = 0;
-	if (clflg != 0)
-		NFSMCLGET(mp, M_WAITOK);
-	else
-		NFSMGET(mp);
+	if (maxext > 0) {
+		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
+		mcp = (char *)(void *)PHYS_TO_DMAP(mp->m_epg_pa[0]);
+		extpg = 0;
+		extpgsiz = PAGE_SIZE;
+	} else {
+		if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
+			clflg = 1;
+		else
+			clflg = 0;
+		if (clflg != 0)
+			NFSMCLGET(mp, M_WAITOK);
+		else
+			NFSMGET(mp);
+		mcp = mtod(mp, char *);
+	}
 	mp->m_len = 0;
 	firstmp = mp2 = mp;
+	rem = NFSM_RNDUP(siz) - siz;
 	while (siz > 0) {
 		left = uiop->uio_iov->iov_len;
 		uiocp = uiop->uio_iov->iov_base;
@@ -187,25 +196,40 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbu
 			left = siz;
 		uiosiz = left;
 		while (left > 0) {
-			mlen = M_TRAILINGSPACE(mp);
-			if (mlen == 0) {
-				if (clflg)
-					NFSMCLGET(mp, M_WAITOK);
-				else
-					NFSMGET(mp);
-				mp->m_len = 0;
-				mp2->m_next = mp;
-				mp2 = mp;
+			if (maxext > 0)
+				mlen = extpgsiz;
+			else
 				mlen = M_TRAILINGSPACE(mp);
+			if (mlen == 0) {
+				if (maxext > 0) {
+					mp = nfsm_add_ext_pgs(mp, maxext,
+					    &extpg);
+					mlen = extpgsiz = PAGE_SIZE;
+					mcp = (char *)(void *)PHYS_TO_DMAP(
+					    mp->m_epg_pa[extpg]);
+				} else {
+					if (clflg)
+						NFSMCLGET(mp, M_WAITOK);
+					else
+						NFSMGET(mp);
+					mcp = mtod(mp, char *);
+					mlen = M_TRAILINGSPACE(mp);
+					mp->m_len = 0;
+					mp2->m_next = mp;
+					mp2 = mp;
+				}
 			}
 			xfer = (left > mlen) ? mlen : left;
 			if (uiop->uio_segflg == UIO_SYSSPACE)
-				NFSBCOPY(uiocp, mtod(mp, caddr_t) +
-				    mp->m_len, xfer);
+				NFSBCOPY(uiocp, mcp, xfer);
 			else
-				copyin(uiocp, mtod(mp, caddr_t) +
-				    mp->m_len, xfer);
+				copyin(uiocp, mcp, xfer);
 			mp->m_len += xfer;
+			mcp += xfer;
+			if (maxext > 0) {
+				extpgsiz -= xfer;
+				mp->m_epg_last_len += xfer;
+			}
 			left -= xfer;
 			uiocp += xfer;
 			uiop->uio_offset += xfer;
@@ -217,10 +241,16 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbu
 		uiop->uio_iov->iov_len -= uiosiz;
 		siz -= uiosiz;
 	}
-	if (cpp != NULL)
-		*cpp = mtod(mp, caddr_t) + mp->m_len;
-	if (mbp != NULL)
-		*mbp = mp;
+	if (rem > 0) {
+		KASSERT((mp->m_flags & M_EXTPG) != 0 ||
+		    rem <= M_TRAILINGSPACE(mp),
+		    ("nfsm_uiombuflist: no space for padding"));
+		for (i = 0; i < rem; i++)
+			*mcp++ = '\0';
+		mp->m_len += rem;
+		if (maxext > 0)
+			mp->m_epg_last_len += rem;
+	}
 	return (firstmp);
 }
 

Modified: projects/nfs-over-tls/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfsclient/nfs_clrpcops.c	Fri Jul 24 01:25:57 2020	(r363469)
+++ projects/nfs-over-tls/sys/fs/nfsclient/nfs_clrpcops.c	Fri Jul 24 02:19:00 2020	(r363470)
@@ -160,7 +160,6 @@ static int nfscl_dofflayoutio(vnode_t, struct uio *, i
     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
     struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
     struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
-static struct mbuf *nfsm_copym(struct mbuf *, int, int);
 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
     struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
     struct ucred *, NFSPROC_T *);
@@ -222,6 +221,7 @@ static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off
     struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
 static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
     int, struct nfsvattr *, int *, struct ucred *);
+static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
 
 int nfs_pnfsio(task_fn_t *, void *);
 
@@ -5759,7 +5759,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 	struct nfscllayout *layp;
 	struct nfscldevinfo *dip;
 	struct nfsclflayout *rflp;
-	struct mbuf *m;
+	struct mbuf *m, *m2;
 	struct nfsclwritedsdorpc *drpc, *tdrpc;
 	nfsv4stateid_t stateid;
 	struct ucred *newcred;
@@ -5865,7 +5865,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 						    uiop->uio_iov->iov_base;
 						iovlen = uiop->uio_iov->iov_len;
 						m = nfsm_uiombuflist(uiop, len,
-						    NULL, NULL);
+						    0);
 					}
 					tdrpc = drpc = malloc(sizeof(*drpc) *
 					    (mirrorcnt - 1), M_TEMP, M_WAITOK |
@@ -5873,6 +5873,13 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 				}
 			}
 			for (i = firstmirror; i < mirrorcnt && error == 0; i++){
+				m2 = NULL;
+				if (m != NULL && i < mirrorcnt - 1)
+					m2 = m_copym(m, 0, M_COPYALL, M_WAITOK);
+				else {
+					m2 = m;
+					m = NULL;
+				}
 				if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) {
 					dev = rflp->nfsfl_ffm[i].dev;
 					dip = nfscl_getdevinfo(nmp->nm_clp, dev,
@@ -5889,7 +5896,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 						    uiop, iomode, must_commit,
 						    &eof, &stateid, rwaccess,
 						    dip, layp, rflp, off, xfer,
-						    i, docommit, m, tdrpc,
+						    i, docommit, m2, tdrpc,
 						    newcred, p);
 					else
 						error = nfscl_doflayoutio(vp,
@@ -5898,8 +5905,11 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 						    dip, layp, rflp, off, xfer,
 						    docommit, newcred, p);
 					nfscl_reldevinfo(dip);
-				} else
+				} else {
+					if (m2 != NULL)
+						m_freem(m2);
 					error = EIO;
+				}
 				tdrpc++;
 			}
 			if (m != NULL)
@@ -5965,38 +5975,6 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode
 }
 
 /*
- * Make a copy of the mbuf chain and add an mbuf for null padding, as required.
- */
-static struct mbuf *
-nfsm_copym(struct mbuf *m, int off, int xfer)
-{
-	struct mbuf *m2, *m3, *m4;
-	uint32_t *tl;
-	int rem;
-
-	m2 = m_copym(m, off, xfer, M_WAITOK);
-	rem = NFSM_RNDUP(xfer) - xfer;
-	if (rem > 0) {
-		/*
-		 * The zero padding to a multiple of 4 bytes is required by
-		 * the XDR. So that the mbufs copied by reference aren't
-		 * modified, add an mbuf with the zero'd bytes to the list.
-		 * rem will be a maximum of 3, so one zero'd uint32_t is
-		 * sufficient.
-		 */
-		m3 = m2;
-		while (m3->m_next != NULL)
-			m3 = m3->m_next;
-		NFSMGET(m4);
-		tl = mtod(m4, uint32_t *);
-		*tl = 0;
-		m4->m_len = rem;
-		m3->m_next = m4;
-	}
-	return (m2);
-}
-
-/*
  * Find a file layout that will handle the first bytes of the requested
  * range and return the information from it needed to the I/O operation.
  */
@@ -6151,17 +6129,17 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *
     uint64_t len, int mirror, int docommit, struct mbuf *mp,
     struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
 {
-	uint64_t transfer, xfer;
-	int error, rel_off;
+	uint64_t xfer;
+	int error;
 	struct nfsnode *np;
 	struct nfsfh *fhp;
 	struct nfsclds **dspp;
 	struct ucred *tcred;
-	struct mbuf *m;
+	struct mbuf *m, *m2;
+	uint32_t copylen;
 
 	np = VTONFS(vp);
 	error = 0;
-	rel_off = 0;
 	NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
 	    (uintmax_t)len);
 	/* Loop around, doing I/O for each stripe unit. */
@@ -6179,14 +6157,31 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *
 		} else
 			tcred = cred;
 		if (rwflag == NFSV4OPEN_ACCESSREAD)
-			transfer = dp->nfsdi_rsize;
-		else
-			transfer = dp->nfsdi_wsize;
+			copylen = dp->nfsdi_rsize;
+		else {
+			copylen = dp->nfsdi_wsize;
+			if (len > copylen && mp != NULL) {
+				/*
+				 * When a mirrored configuration needs to do
+				 * multiple writes to each mirror, all writes
+				 * except the last one must be a multiple of
+				 * 4 bytes.  This is required so that the XDR
+				 * does not need padding.
+				 * If possible, clip the size to an exact
+				 * multiple of the mbuf length, so that the
+				 * split will be on an mbuf boundary.
+				 */
+				copylen &= 0xfffffffc;
+				if (copylen > mp->m_len)
+					copylen = copylen / mp->m_len *
+					    mp->m_len;
+			}
+		}
 		NFSLOCKNODE(np);
 		np->n_flag |= NDSCOMMIT;
 		NFSUNLOCKNODE(np);
-		if (len > transfer && docommit == 0)
-			xfer = transfer;
+		if (len > copylen && docommit == 0)
+			xfer = copylen;
 		else
 			xfer = len;
 		if (docommit != 0) {
@@ -6247,31 +6242,41 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *
 					NFSUNLOCKCLSTATE();
 				}
 			} else {
-				m = nfsm_copym(mp, rel_off, xfer);
-				NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n",
-				    rel_off, (uintmax_t)xfer);
+				m = mp;
+				if (xfer < len) {
+					/* The mbuf list must be split. */
+					m2 = nfsm_split(mp, xfer);
+					if (m2 != NULL)
+						mp = m2;
+					else {
+						m_freem(mp);
+						error = EIO;
+					}
+				}
+				NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n",
+				    (uintmax_t)len, (uintmax_t)xfer);
 				/*
-				 * Do the writes after the first loop iteration
-				 * and the write for the last mirror via this
+				 * Do last write to a mirrored DS with this
 				 * thread.
-				 * This loop only iterates for small values
-				 * of nfsdi_wsize, which may never occur in
-				 * practice.  However, the drpc is completely
-				 * used by the first iteration and, as such,
-				 * cannot be used after that.
 				 */
-				if (mirror < flp->nfsfl_mirrorcnt - 1 &&
-				    rel_off == 0)
-					error = nfsio_writedsmir(vp, iomode,
-					    must_commit, stateidp, *dspp, off,
-					    xfer, fhp, m, dp->nfsdi_vers,
-					    dp->nfsdi_minorvers, drpc, tcred,
-					    p);
-				else
-					error = nfsrpc_writedsmir(vp, iomode,
-					    must_commit, stateidp, *dspp, off,
-					    xfer, fhp, m, dp->nfsdi_vers,
-					    dp->nfsdi_minorvers, tcred, p);
+				if (error == 0) {
+					if (mirror < flp->nfsfl_mirrorcnt - 1)
+						error = nfsio_writedsmir(vp,
+						    iomode, must_commit,
+						    stateidp, *dspp, off,
+						    xfer, fhp, m,
+						    dp->nfsdi_vers,
+						    dp->nfsdi_minorvers, drpc,
+						    tcred, p);
+					else
+						error = nfsrpc_writedsmir(vp,
+						    iomode, must_commit,
+						    stateidp, *dspp, off,
+						    xfer, fhp, m,
+						    dp->nfsdi_vers,
+						    dp->nfsdi_minorvers, tcred,
+						    p);
+				}
 				NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error);
 				if (error != 0 && error != EACCES && error !=
 				    ESTALE) {
@@ -6286,7 +6291,6 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *
 		if (error == 0) {
 			len -= xfer;
 			off += xfer;
-			rel_off += xfer;
 		}
 		if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
 			NFSFREECRED(tcred);
@@ -6544,12 +6548,6 @@ nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_c
 	if (len > 0) {
 		/* Put data in mbuf chain. */
 		nd->nd_mb->m_next = m;
-		/* Set nd_mb and nd_bpos to end of data. */
-		while (m->m_next != NULL)
-			m = m->m_next;
-		nd->nd_mb = m;
-		nd->nd_bpos = mtod(m, char *) + m->m_len;
-		NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len);
 	}
 	nrp = dsp->nfsclds_sockp;
 	if (nrp == NULL)
@@ -8626,3 +8624,103 @@ nfsmout:
 	return (error);
 }
 
+/*
+ * Split an mbuf list.  For non-M_EXTPG mbufs, just use m_split().
+ */
+static struct mbuf *
+nfsm_split(struct mbuf *mp, uint64_t xfer)
+{
+	struct mbuf *m, *m2;
+	vm_page_t pg;
+	int i, j, left, pgno, plen, trim;
+	char *cp, *cp2;
+
+	if ((mp->m_flags & M_EXTPG) == 0) {
+		m = m_split(mp, xfer, M_WAITOK);
+		return (m);
+	}
+
+	/* Find the correct mbuf to split at. */
+	for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next)
+		xfer -= m->m_len;
+	if (m == NULL)
+		return (NULL);
+
+	/* If xfer == m->m_len, we can just split the mbuf list. */
+	if (xfer == m->m_len) {
+		m2 = m->m_next;
+		m->m_next = NULL;
+		return (m2);
+	}
+
+	/* Find the page to split at. */
+	pgno = 0;
+	left = xfer;
+	do {
+		if (pgno == 0)
+			plen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
+		else
+			plen = m_epg_pagelen(m, pgno, 0);
+		if (left <= plen)
+			break;
+		left -= plen;
+		pgno++;
+	} while (pgno < m->m_epg_npgs);
+	if (pgno == m->m_epg_npgs)
+		panic("nfsm_split: eroneous ext_pgs mbuf");
+
+	m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs);
+	m2->m_epg_flags |= EPG_FLAG_ANON;
+
+	/*
+	 * If left < plen, allocate a new page for the new mbuf
+	 * and copy the data after left in the page to this new
+	 * page.
+	 */
+	if (left < plen) {
+		do {
+			pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+			    VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
+			    VM_ALLOC_WIRED);
+			if (pg == NULL)
+				vm_wait(NULL);
+		} while (pg == NULL);
+		m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg);
+		m2->m_epg_npgs = 1;
+
+		/* Copy the data after left to the new page. */
+		trim = plen - left;
+		cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
+		if (pgno == 0)
+			cp += m->m_epg_1st_off;
+		cp += left;
+		cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]);
+		if (pgno == m->m_epg_npgs - 1)
+			m2->m_epg_last_len = trim;
+		else {
+			cp2 += PAGE_SIZE - trim;
+			m2->m_epg_1st_off = PAGE_SIZE - trim;
+			m2->m_epg_last_len = m->m_epg_last_len;
+		}
+		memcpy(cp2, cp, trim);
+		m2->m_len = trim;
+	} else {
+		m2->m_len = 0;
+		m2->m_epg_last_len = m->m_epg_last_len;
+	}
+
+	/* Move the pages beyond pgno to the new mbuf. */
+	for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) {
+		m2->m_epg_pa[j] = m->m_epg_pa[i];
+		/* Never moves page 0. */
+		m2->m_len += m_epg_pagelen(m, i, 0);
+	}
+	m2->m_epg_npgs = j;
+	m->m_epg_npgs = pgno + 1;
+	m->m_epg_last_len = left;
+	m->m_len = xfer;
+
+	m2->m_next = m->m_next;
+	m->m_next = NULL;
+	return (m2);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202007240219.06O2J14h056914>