svn commit: r358768 - in projects/nfs-over-tls/sys: kern sys
Rick Macklem
rmacklem at FreeBSD.org
Sun Mar 8 18:52:06 UTC 2020
Author: rmacklem
Date: Sun Mar 8 18:52:04 2020
New Revision: 358768
URL: https://svnweb.freebsd.org/changeset/base/358768
Log:
Add mb_splitatpos_extpgs() to kern_mbuf.c. It is similar to m_split(),
but handles ext_pgs mbufs with anonymous pages. It does not duplicate
the m_pkthdr mbuf, since that could result in an mbuf with m_len == 0
and npgs == 0, which does not seem to be allowed by certain sanity
checks on ext_pgs mbuf chains.
For my uses, I do not need an m_pkthdr mbuf.
Modified:
projects/nfs-over-tls/sys/kern/kern_mbuf.c
projects/nfs-over-tls/sys/sys/mbuf.h
Modified: projects/nfs-over-tls/sys/kern/kern_mbuf.c
==============================================================================
--- projects/nfs-over-tls/sys/kern/kern_mbuf.c Sun Mar 8 18:48:01 2020 (r358767)
+++ projects/nfs-over-tls/sys/kern/kern_mbuf.c Sun Mar 8 18:52:04 2020 (r358768)
@@ -1679,6 +1679,8 @@ mb_copym_ext_pgs(struct mbuf *mp, int len, int mlen, i
m_freem(mout);
return (NULL);
}
+ KASSERT((mp->m_flags & M_NOMAP) == 0,
+ ("mb_copym_ext_pgs: ext_pgs input mbuf"));
mbpos = mtod(mp, char *);
mblen = mp->m_len;
mp = mp->m_next;
@@ -1696,4 +1698,120 @@ mb_copym_ext_pgs(struct mbuf *mp, int len, int mlen, i
if (mlast != NULL)
*mlast = m;
return (mout);
+}
+
+/*
+ * Split an ext_pgs mbuf list into two lists at len bytes.
+ * Similar to m_split(), but for ext_pgs mbufs with
+ * anonymous pages.
+ */
+struct mbuf *
+mb_splitatpos_ext(struct mbuf *m0, int len, int how)
+{
+ struct mbuf *m, *mp;
+ struct mbuf_ext_pgs *pgs, *pgs0;
+ vm_page_t pg;
+ int i, j, left, pgno, plen, trim;
+ char *cp, *cp0;
+
+ /* Nothing to do. */
+ if (len == 0)
+ return (NULL);
+
+ /* Find the correct mbuf to split at. */
+ for (mp = m0; mp != NULL && len > mp->m_len; mp = mp->m_next)
+ len -= mp->m_len;
+ if (mp == NULL)
+ return (NULL);
+
+ /* If len == mp->m_len, we can just split the mbuf list. */
+ if (len == mp->m_len) {
+ m = mp->m_next;
+ mp->m_next = NULL;
+ return (m);
+ }
+
+ /* Find the page to split at. */
+ KASSERT((mp->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP),
+ ("mb_splitatpos_ext: m0 not ext_pgs"));
+ pgs = mp->m_ext.ext_pgs;
+ KASSERT((pgs->flags & MBUF_PEXT_FLAG_ANON) != 0,
+ ("mb_splitatpos_ext: not anonymous pages"));
+ pgno = 0;
+ left = len;
+ do {
+ if (pgno == 0)
+ plen = mbuf_ext_pg_len(pgs, 0,
+ pgs->first_pg_off);
+ else
+ plen = mbuf_ext_pg_len(pgs, pgno, 0);
+ if (left <= plen)
+ break;
+ left -= plen;
+ pgno++;
+ } while (pgno < pgs->npgs);
+ if (pgno == pgs->npgs)
+ panic("mb_splitatpos_ext");
+ mp->m_len = len;
+
+ m = mb_alloc_ext_pgs(how, false, mb_free_mext_pgs);
+ if (m == NULL)
+ return (NULL);
+ pgs0 = m->m_ext.ext_pgs;
+ pgs0->flags |= MBUF_PEXT_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) {
+ if (how == M_NOWAIT) {
+ m_free(m);
+ return (NULL);
+ }
+ vm_wait(NULL);
+ }
+ } while (pg == NULL);
+ pgs0->pa[0] = VM_PAGE_TO_PHYS(pg);
+ pgs0->npgs++;
+ trim = plen - left;
+ cp = (char *)(void *)PHYS_TO_DMAP(pgs->pa[pgno]);
+ cp0 = (char *)(void *)PHYS_TO_DMAP(pgs0->pa[0]);
+ if (pgno == 0)
+ cp += pgs->first_pg_off;
+ cp += left;
+ if (pgno == pgs->npgs - 1)
+ pgs0->last_pg_len = trim;
+ else {
+ pgs0->last_pg_len = pgs->last_pg_len;
+ pgs0->first_pg_off = PAGE_SIZE - trim;
+ cp0 += PAGE_SIZE - trim;
+ }
+ memcpy(cp0, cp, trim);
+ m->m_len = trim;
+ } else
+ pgs0->last_pg_len = pgs->last_pg_len;
+
+ /* Move the pages beyond pgno to the new mbuf. */
+ for (i = pgno + 1, j = pgs0->npgs; i < pgs->npgs; i++, j++) {
+ pgs0->pa[j] = pgs->pa[i];
+ /* Never moves page 0. */
+ m->m_len += mbuf_ext_pg_len(pgs, i, 0);
+ }
+ pgs0->npgs = j;
+ pgs->npgs = pgno + 1;
+
+ /* Can now update pgs->last_pg_len. */
+ pgs->last_pg_len = left;
+
+ m->m_next = mp->m_next;
+ mp->m_next = NULL;
+ return (m);
}
Modified: projects/nfs-over-tls/sys/sys/mbuf.h
==============================================================================
--- projects/nfs-over-tls/sys/sys/mbuf.h Sun Mar 8 18:48:01 2020 (r358767)
+++ projects/nfs-over-tls/sys/sys/mbuf.h Sun Mar 8 18:52:04 2020 (r358768)
@@ -703,6 +703,7 @@ struct mbuf *mb_alloc_ext_pgs(int, bool, m_ext_free_t)
struct mbuf *mb_alloc_ext_plus_pages(int, int, bool, m_ext_free_t);
struct mbuf *mb_copym_ext_pgs(struct mbuf *, int, int, int, bool,
m_ext_free_t, struct mbuf **);
+struct mbuf *mb_splitatpos_ext(struct mbuf *, int, int);
int mb_unmapped_compress(struct mbuf *m);
struct mbuf *mb_unmapped_to_ext(struct mbuf *m);
void mb_free_notready(struct mbuf *m, int count);
More information about the svn-src-projects
mailing list