Author: rmacklem
Date: Wed Jun 10 02:51:39 2020
New Revision: 361998
URL: https://svnweb.freebsd.org/changeset/base/361998

Log:
  Add two functions that create M_EXTPG mbufs with anonymous pages.
  
  These two functions are needed by nfs-over-tls, but could also be
  useful for other purposes.
  mb_alloc_ext_plus_pages() - Allocates a M_EXTPG mbuf and enough anonymous
        pages to store "len" data bytes.
  mb_mapped_to_unmapped() - Copies the data from a list of mapped (non-M_EXTPG)
        mbufs into a list of M_EXTPG mbufs allocated with anonymous pages.
        This is roughly the inverse of mb_unmapped_to_ext().
  
  Reviewed by:  gallatin
  Differential Revision:        https://reviews.freebsd.org/D25182

Modified:
  head/sys/kern/kern_mbuf.c
  head/sys/sys/mbuf.h

Modified: head/sys/kern/kern_mbuf.c
==============================================================================
--- head/sys/kern/kern_mbuf.c   Wed Jun 10 02:50:25 2020        (r361997)
+++ head/sys/kern/kern_mbuf.c   Wed Jun 10 02:51:39 2020        (r361998)
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_extern.h>
 #include <vm/vm_kern.h>
 #include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
 #include <vm/vm_map.h>
 #include <vm/uma.h>
 #include <vm/uma_dbg.h>
@@ -1536,4 +1537,105 @@ m_snd_tag_destroy(struct m_snd_tag *mst)
        ifp->if_snd_tag_free(mst);
        if_rele(ifp);
        counter_u64_add(snd_tag_count, -1);
+}
+
+/*
+ * Allocate an mbuf with anonymous external pages.
+ */
+struct mbuf *
+mb_alloc_ext_plus_pages(int len, int how)
+{
+       struct mbuf *m;
+       vm_page_t pg;
+       int i, npgs;
+
+       m = mb_alloc_ext_pgs(how, mb_free_mext_pgs);
+       if (m == NULL)
+               return (NULL);
+       m->m_epg_flags |= EPG_FLAG_ANON;
+       npgs = howmany(len, PAGE_SIZE);
+       for (i = 0; i < npgs; i++) {
+               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->m_epg_npgs = i;
+                                       m_free(m);
+                                       return (NULL);
+                               }
+                               vm_wait(NULL);
+                       }
+               } while (pg == NULL);
+               m->m_epg_pa[i] = VM_PAGE_TO_PHYS(pg);
+       }
+       m->m_epg_npgs = npgs;
+       return (m);
+}
+
+/*
+ * Copy the data in the mbuf chain to a chain of mbufs with anonymous external
+ * unmapped pages.
+ * len is the length of data in the input mbuf chain.
+ * mlen is the maximum number of bytes put into each ext_page mbuf.
+ */
+struct mbuf *
+mb_mapped_to_unmapped(struct mbuf *mp, int len, int mlen, int how,
+    struct mbuf **mlast)
+{
+       struct mbuf *m, *mout;
+       char *pgpos, *mbpos;
+       int i, mblen, mbufsiz, pglen, xfer;
+
+       if (len == 0)
+               return (NULL);
+       mbufsiz = min(mlen, len);
+       m = mout = mb_alloc_ext_plus_pages(mbufsiz, how);
+       if (m == NULL)
+               return (m);
+       pgpos = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[0]);
+       pglen = PAGE_SIZE;
+       mblen = 0;
+       i = 0;
+       do {
+               if (pglen == 0) {
+                       if (++i == m->m_epg_npgs) {
+                               m->m_epg_last_len = PAGE_SIZE;
+                               mbufsiz = min(mlen, len);
+                               m->m_next = mb_alloc_ext_plus_pages(mbufsiz,
+                                   how);
+                               m = m->m_next;
+                               if (m == NULL) {
+                                       m_freem(mout);
+                                       return (m);
+                               }
+                               i = 0;
+                       }
+                       pgpos = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[i]);
+                       pglen = PAGE_SIZE;
+               }
+               while (mblen == 0) {
+                       if (mp == NULL) {
+                               m_freem(mout);
+                               return (NULL);
+                       }
+                       KASSERT((mp->m_flags & M_EXTPG) == 0,
+                           ("mb_copym_ext_pgs: ext_pgs input mbuf"));
+                       mbpos = mtod(mp, char *);
+                       mblen = mp->m_len;
+                       mp = mp->m_next;
+               }
+               xfer = min(mblen, pglen);
+               memcpy(pgpos, mbpos, xfer);
+               pgpos += xfer;
+               mbpos += xfer;
+               pglen -= xfer;
+               mblen -= xfer;
+               len -= xfer;
+               m->m_len += xfer;
+       } while (len > 0);
+       m->m_epg_last_len = PAGE_SIZE - pglen;
+       if (mlast != NULL)
+               *mlast = m;
+       return (mout);
 }

Modified: head/sys/sys/mbuf.h
==============================================================================
--- head/sys/sys/mbuf.h Wed Jun 10 02:50:25 2020        (r361997)
+++ head/sys/sys/mbuf.h Wed Jun 10 02:51:39 2020        (r361998)
@@ -741,6 +741,9 @@ void                 mb_free_ext(struct mbuf *);
 void            mb_free_extpg(struct mbuf *);
 void            mb_free_mext_pgs(struct mbuf *);
 struct mbuf    *mb_alloc_ext_pgs(int, m_ext_free_t);
+struct mbuf    *mb_alloc_ext_plus_pages(int, int);
+struct mbuf    *mb_mapped_to_unmapped(struct mbuf *, int, int, int,
+                   struct mbuf **);
 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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to