glebius created this revision.
glebius added a reviewer: gnn.
Herald added a subscriber: imp.
Herald added a reviewer: transport.

REVISION SUMMARY
  Before upcoming changes to mbuf(9) gather all allocation APIs
  into kern_mbuf.c, and declare them in sys/mbuf.h
  
  The uipc_mbuf.c now will have only mbuf manipulation routines.
  sys/mbuf.h has only declaration and doesn't diclose internal
  allocator structures.

TEST PLAN
  Since inlining level has reduced, benchmarking is required.

REPOSITORY
  rS FreeBSD src repository

BRANCH
  /head

REVISION DETAIL
  https://reviews.freebsd.org/D5180

AFFECTED FILES
  sys/dev/cxgb/cxgb_adapter.h
  sys/dev/cxgb/cxgb_sge.c
  sys/dev/cxgbe/t4_netmap.c
  sys/dev/cxgbe/t4_sge.c
  sys/dev/netmap/netmap_generic.c
  sys/kern/kern_mbuf.c
  sys/kern/uipc_mbuf.c
  sys/netinet/tcp_pcap.c
  sys/sys/mbuf.h

EMAIL PREFERENCES
  https://reviews.freebsd.org/settings/panel/emailpreferences/

To: glebius, transport, gnn
Cc: imp
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -38,7 +38,6 @@
 #include <sys/queue.h>
 #ifdef _KERNEL
 #include <sys/systm.h>
-#include <vm/uma.h>
 #ifdef WITNESS
 #include <sys/lock.h>
 #endif
@@ -81,15 +80,6 @@
  */
 #define	mtod(m, t)	((t)((m)->m_data))
 #define	mtodo(m, o)	((void *)(((m)->m_data) + (o)))
-
-/*
- * Argument structure passed to UMA routines during mbuf and packet
- * allocations.
- */
-struct mb_args {
-	int	flags;	/* Flags for mbuf being allocated */
-	short	type;	/* Type of mbuf being allocated */
-};
 #endif /* _KERNEL */
 
 /*
@@ -513,23 +503,6 @@
 #define	MBUF_CHECKSLEEP(how)
 #endif
 
-/*
- * Network buffer allocation API
- *
- * The rest of it is defined in kern/kern_mbuf.c
- */
-extern uma_zone_t	zone_mbuf;
-extern uma_zone_t	zone_clust;
-extern uma_zone_t	zone_pack;
-extern uma_zone_t	zone_jumbop;
-extern uma_zone_t	zone_jumbo9;
-extern uma_zone_t	zone_jumbo16;
-extern uma_zone_t	zone_ext_refcnt;
-
-void		 mb_dupcl(struct mbuf *, const struct mbuf *);
-void		 mb_free_ext(struct mbuf *);
-int		 m_pkthdr_init(struct mbuf *, int);
-
 static __inline int
 m_gettype(int size)
 {
@@ -583,188 +556,6 @@
 	m->m_ext.ext_flags = 0;
 }
 
-static __inline uma_zone_t
-m_getzone(int size)
-{
-	uma_zone_t zone;
-
-	switch (size) {
-	case MCLBYTES:
-		zone = zone_clust;
-		break;
-#if MJUMPAGESIZE != MCLBYTES
-	case MJUMPAGESIZE:
-		zone = zone_jumbop;
-		break;
-#endif
-	case MJUM9BYTES:
-		zone = zone_jumbo9;
-		break;
-	case MJUM16BYTES:
-		zone = zone_jumbo16;
-		break;
-	default:
-		panic("%s: invalid cluster size %d", __func__, size);
-	}
-
-	return (zone);
-}
-
-/*
- * Initialize an mbuf with linear storage.
- *
- * Inline because the consumer text overhead will be roughly the same to
- * initialize or call a function with this many parameters and M_PKTHDR
- * should go away with constant propagation for !MGETHDR.
- */
-static __inline int
-m_init(struct mbuf *m, uma_zone_t zone __unused, int size __unused, int how,
-    short type, int flags)
-{
-	int error;
-
-	m->m_next = NULL;
-	m->m_nextpkt = NULL;
-	m->m_data = m->m_dat;
-	m->m_len = 0;
-	m->m_flags = flags;
-	m->m_type = type;
-	if (flags & M_PKTHDR) {
-		if ((error = m_pkthdr_init(m, how)) != 0)
-			return (error);
-	}
-
-	return (0);
-}
-
-static __inline struct mbuf *
-m_get(int how, short type)
-{
-	struct mb_args args;
-
-	args.flags = 0;
-	args.type = type;
-	return (uma_zalloc_arg(zone_mbuf, &args, how));
-}
-
-/*
- * XXX This should be deprecated, very little use.
- */
-static __inline struct mbuf *
-m_getclr(int how, short type)
-{
-	struct mbuf *m;
-	struct mb_args args;
-
-	args.flags = 0;
-	args.type = type;
-	m = uma_zalloc_arg(zone_mbuf, &args, how);
-	if (m != NULL)
-		bzero(m->m_data, MLEN);
-	return (m);
-}
-
-static __inline struct mbuf *
-m_gethdr(int how, short type)
-{
-	struct mb_args args;
-
-	args.flags = M_PKTHDR;
-	args.type = type;
-	return (uma_zalloc_arg(zone_mbuf, &args, how));
-}
-
-static __inline struct mbuf *
-m_getcl(int how, short type, int flags)
-{
-	struct mb_args args;
-
-	args.flags = flags;
-	args.type = type;
-	return (uma_zalloc_arg(zone_pack, &args, how));
-}
-
-static __inline int
-m_clget(struct mbuf *m, int how)
-{
-
-	KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
-	    __func__, m));
-	m->m_ext.ext_buf = (char *)NULL;
-	uma_zalloc_arg(zone_clust, m, how);
-	/*
-	 * On a cluster allocation failure, drain the packet zone and retry,
-	 * we might be able to loosen a few clusters up on the drain.
-	 */
-	if ((how & M_NOWAIT) && (m->m_ext.ext_buf == NULL)) {
-		zone_drain(zone_pack);
-		uma_zalloc_arg(zone_clust, m, how);
-	}
-	return (m->m_flags & M_EXT);
-}
-
-/*
- * m_cljget() is different from m_clget() as it can allocate clusters without
- * attaching them to an mbuf.  In that case the return value is the pointer
- * to the cluster of the requested size.  If an mbuf was specified, it gets
- * the cluster attached to it and the return value can be safely ignored.
- * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
- */
-static __inline void *
-m_cljget(struct mbuf *m, int how, int size)
-{
-	uma_zone_t zone;
-
-	if (m != NULL) {
-		KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
-		    __func__, m));
-		m->m_ext.ext_buf = NULL;
-	}
-
-	zone = m_getzone(size);
-	return (uma_zalloc_arg(zone, m, how));
-}
-
-static __inline void
-m_cljset(struct mbuf *m, void *cl, int type)
-{
-	uma_zone_t zone;
-	int size;
-
-	switch (type) {
-	case EXT_CLUSTER:
-		size = MCLBYTES;
-		zone = zone_clust;
-		break;
-#if MJUMPAGESIZE != MCLBYTES
-	case EXT_JUMBOP:
-		size = MJUMPAGESIZE;
-		zone = zone_jumbop;
-		break;
-#endif
-	case EXT_JUMBO9:
-		size = MJUM9BYTES;
-		zone = zone_jumbo9;
-		break;
-	case EXT_JUMBO16:
-		size = MJUM16BYTES;
-		zone = zone_jumbo16;
-		break;
-	default:
-		panic("%s: unknown cluster type %d", __func__, type);
-		break;
-	}
-
-	m->m_data = m->m_ext.ext_buf = cl;
-	m->m_ext.ext_free = m->m_ext.ext_arg1 = m->m_ext.ext_arg2 = NULL;
-	m->m_ext.ext_size = size;
-	m->m_ext.ext_type = type;
-	m->m_ext.ext_flags = 0;
-	m->m_ext.ext_cnt = uma_find_refcnt(zone, cl);
-	m->m_flags |= M_EXT;
-
-}
-
 static __inline void
 m_chtype(struct mbuf *m, short new_type)
 {
@@ -944,15 +735,15 @@
 
 struct uio;
 
+void		 mb_dupcl(struct mbuf *, const struct mbuf *);
 void		 m_adj(struct mbuf *, int);
 int		 m_apply(struct mbuf *, int, int,
 		    int (*)(void *, void *, u_int), void *);
 int		 m_append(struct mbuf *, int, c_caddr_t);
 void		 m_cat(struct mbuf *, struct mbuf *);
 void		 m_catpkt(struct mbuf *, struct mbuf *);
-int		 m_extadd(struct mbuf *, caddr_t, u_int,
-		    void (*)(struct mbuf *, void *, void *), void *, void *,
-		    int, int, int);
+int		 m_clget(struct mbuf *m, int how);
+void 		*m_cljget(struct mbuf *m, int how, int size);
 struct mbuf	*m_collapse(struct mbuf *, int, int);
 void		 m_copyback(struct mbuf *, int, int, c_caddr_t);
 void		 m_copydata(const struct mbuf *, int, int, caddr_t);
@@ -967,13 +758,21 @@
 		    void (*)(char *, caddr_t, u_int));
 struct mbuf	*m_dup(const struct mbuf *, int);
 int		 m_dup_pkthdr(struct mbuf *, const struct mbuf *, int);
+int		 m_extadd(struct mbuf *, caddr_t, u_int,
+		    void (*)(struct mbuf *, void *, void *), void *, void *,
+		    int, int, int);
 u_int		 m_fixhdr(struct mbuf *);
 struct mbuf	*m_fragment(struct mbuf *, int, int);
+struct mbuf	*m_free(struct mbuf *);
 void		 m_freem(struct mbuf *);
 struct mbuf	*m_get2(int, int, short, int);
 struct mbuf	*m_getjcl(int, short, int, int);
 struct mbuf	*m_getm2(struct mbuf *, int, int, short, int);
 struct mbuf	*m_getptr(struct mbuf *, int, int *);
+struct mbuf 	*m_get(int how, short type);
+struct mbuf 	*m_getcl(int how, short type, int flags);
+struct mbuf 	*m_gethdr(int how, short type);
+int		 m_init(struct mbuf *m, int how, short type, int flags);
 u_int		 m_length(struct mbuf *, struct mbuf **);
 int		 m_mbuftouio(struct uio *, struct mbuf *, int);
 void		 m_move_pkthdr(struct mbuf *, struct mbuf *);
@@ -1167,20 +966,6 @@
 	    m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
 }
 
-static __inline struct mbuf *
-m_free(struct mbuf *m)
-{
-	struct mbuf *n = m->m_next;
-
-	if ((m->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
-		m_tag_delete_chain(m, NULL);
-	if (m->m_flags & M_EXT)
-		mb_free_ext(m);
-	else if ((m->m_flags & M_NOFREE) == 0)
-		uma_zfree(zone_mbuf, m);
-	return (n);
-}
-
 static __inline int
 rt_m_getfib(struct mbuf *m)
 {
diff --git a/sys/netinet/tcp_pcap.c b/sys/netinet/tcp_pcap.c
--- a/sys/netinet/tcp_pcap.c
+++ b/sys/netinet/tcp_pcap.c
@@ -341,7 +341,10 @@
 
 			n = mhead;
 			tcp_pcap_m_freem(n->m_next);
-			m_init(n, NULL, 0, M_NOWAIT, MT_DATA, 0);
+			m->m_next = NULL;
+			m->m_nextpkt = NULL;
+			m->m_len = 0;
+			m->m_flags = 0;
 		}
 	}
 
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -48,6 +48,8 @@
 #include <sys/protosw.h>
 #include <sys/uio.h>
 
+#include <security/mac/mac_framework.h>
+
 int	max_linkhdr;
 int	max_protohdr;
 int	max_hdr;
@@ -132,266 +134,32 @@
 #endif
 
 /*
- * m_get2() allocates minimum mbuf that would fit "size" argument.
- */
-struct mbuf *
-m_get2(int size, int how, short type, int flags)
-{
-	struct mb_args args;
-	struct mbuf *m, *n;
-
-	args.flags = flags;
-	args.type = type;
-
-	if (size <= MHLEN || (size <= MLEN && (flags & M_PKTHDR) == 0))
-		return (uma_zalloc_arg(zone_mbuf, &args, how));
-	if (size <= MCLBYTES)
-		return (uma_zalloc_arg(zone_pack, &args, how));
-
-	if (size > MJUMPAGESIZE)
-		return (NULL);
-
-	m = uma_zalloc_arg(zone_mbuf, &args, how);
-	if (m == NULL)
-		return (NULL);
-
-	n = uma_zalloc_arg(zone_jumbop, m, how);
-	if (n == NULL) {
-		uma_zfree(zone_mbuf, m);
-		return (NULL);
-	}
-
-	return (m);
-}
-
-/*
- * m_getjcl() returns an mbuf with a cluster of the specified size attached.
- * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
- */
-struct mbuf *
-m_getjcl(int how, short type, int flags, int size)
-{
-	struct mb_args args;
-	struct mbuf *m, *n;
-	uma_zone_t zone;
-
-	if (size == MCLBYTES)
-		return m_getcl(how, type, flags);
-
-	args.flags = flags;
-	args.type = type;
-
-	m = uma_zalloc_arg(zone_mbuf, &args, how);
-	if (m == NULL)
-		return (NULL);
-
-	zone = m_getzone(size);
-	n = uma_zalloc_arg(zone, m, how);
-	if (n == NULL) {
-		uma_zfree(zone_mbuf, m);
-		return (NULL);
-	}
-	return (m);
-}
-
-/*
- * Allocate a given length worth of mbufs and/or clusters (whatever fits
- * best) and return a pointer to the top of the allocated chain.  If an
- * existing mbuf chain is provided, then we will append the new chain
- * to the existing one but still return the top of the newly allocated
- * chain.
- */
-struct mbuf *
-m_getm2(struct mbuf *m, int len, int how, short type, int flags)
-{
-	struct mbuf *mb, *nm = NULL, *mtail = NULL;
-
-	KASSERT(len >= 0, ("%s: len is < 0", __func__));
-
-	/* Validate flags. */
-	flags &= (M_PKTHDR | M_EOR);
-
-	/* Packet header mbuf must be first in chain. */
-	if ((flags & M_PKTHDR) && m != NULL)
-		flags &= ~M_PKTHDR;
-
-	/* Loop and append maximum sized mbufs to the chain tail. */
-	while (len > 0) {
-		if (len > MCLBYTES)
-			mb = m_getjcl(how, type, (flags & M_PKTHDR),
-			    MJUMPAGESIZE);
-		else if (len >= MINCLSIZE)
-			mb = m_getcl(how, type, (flags & M_PKTHDR));
-		else if (flags & M_PKTHDR)
-			mb = m_gethdr(how, type);
-		else
-			mb = m_get(how, type);
-
-		/* Fail the whole operation if one mbuf can't be allocated. */
-		if (mb == NULL) {
-			if (nm != NULL)
-				m_freem(nm);
-			return (NULL);
-		}
-
-		/* Book keeping. */
-		len -= M_SIZE(mb);
-		if (mtail != NULL)
-			mtail->m_next = mb;
-		else
-			nm = mb;
-		mtail = mb;
-		flags &= ~M_PKTHDR;	/* Only valid on the first mbuf. */
-	}
-	if (flags & M_EOR)
-		mtail->m_flags |= M_EOR;  /* Only valid on the last mbuf. */
-
-	/* If mbuf was supplied, append new chain to the end of it. */
-	if (m != NULL) {
-		for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next)
-			;
-		mtail->m_next = nm;
-		mtail->m_flags &= ~M_EOR;
-	} else
-		m = nm;
-
-	return (m);
-}
-
-/*
- * Free an entire chain of mbufs and associated external buffers, if
- * applicable.
- */
-void
-m_freem(struct mbuf *mb)
-{
-
-	while (mb != NULL)
-		mb = m_free(mb);
-}
-
-/*-
- * Configure a provided mbuf to refer to the provided external storage
- * buffer and setup a reference count for said buffer.  If the setting
- * up of the reference count fails, the M_EXT bit will not be set.  If
- * successfull, the M_EXT bit is set in the mbuf's flags.
- *
- * Arguments:
- *    mb     The existing mbuf to which to attach the provided buffer.
- *    buf    The address of the provided external storage buffer.
- *    size   The size of the provided buffer.
- *    freef  A pointer to a routine that is responsible for freeing the
- *           provided external storage buffer.
- *    args   A pointer to an argument structure (of any type) to be passed
- *           to the provided freef routine (may be NULL).
- *    flags  Any other flags to be passed to the provided mbuf.
- *    type   The type that the external storage buffer should be
- *           labeled with.
- *
- * Returns:
- *    Nothing.
+ * Initialize an mbuf with linear storage.
  */
 int
-m_extadd(struct mbuf *mb, caddr_t buf, u_int size,
-    void (*freef)(struct mbuf *, void *, void *), void *arg1, void *arg2,
-    int flags, int type, int wait)
-{
-	KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__));
-
-	if (type != EXT_EXTREF)
-		mb->m_ext.ext_cnt = uma_zalloc(zone_ext_refcnt, wait);
-
-	if (mb->m_ext.ext_cnt == NULL)
-		return (ENOMEM);
-
-	*(mb->m_ext.ext_cnt) = 1;
-	mb->m_flags |= (M_EXT | flags);
-	mb->m_ext.ext_buf = buf;
-	mb->m_data = mb->m_ext.ext_buf;
-	mb->m_ext.ext_size = size;
-	mb->m_ext.ext_free = freef;
-	mb->m_ext.ext_arg1 = arg1;
-	mb->m_ext.ext_arg2 = arg2;
-	mb->m_ext.ext_type = type;
-	mb->m_ext.ext_flags = 0;
-
-	return (0);
-}
-
-/*
- * Non-directly-exported function to clean up after mbufs with M_EXT
- * storage attached to them if the reference count hits 1.
- */
-void
-mb_free_ext(struct mbuf *m)
+m_init(struct mbuf *m, int how, short type, int flags)
 {
-	int freembuf;
-
-	KASSERT(m->m_flags & M_EXT, ("%s: M_EXT not set on %p", __func__, m));
 
-	/*
-	 * Check if the header is embedded in the cluster.
-	 */
-	freembuf = (m->m_flags & M_NOFREE) ? 0 : 1;
-
-	switch (m->m_ext.ext_type) {
-	case EXT_SFBUF:
-		sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
-		break;
-	case EXT_SFBUF_NOCACHE:
-		sf_ext_free_nocache(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
-		break;
-	default:
-		KASSERT(m->m_ext.ext_cnt != NULL,
-		    ("%s: no refcounting pointer on %p", __func__, m));
-		/* 
-		 * Free attached storage if this mbuf is the only
-		 * reference to it.
-		 */
-		if (*(m->m_ext.ext_cnt) != 1) {
-			if (atomic_fetchadd_int(m->m_ext.ext_cnt, -1) != 1)
-				break;
-		}
+	m->m_next = NULL;
+	m->m_nextpkt = NULL;
+	m->m_data = m->m_dat;
+	m->m_len = 0;
+	m->m_flags = flags;
+	m->m_type = type;
+	if (flags & M_PKTHDR) {
+		int error;
 
-		switch (m->m_ext.ext_type) {
-		case EXT_PACKET:	/* The packet zone is special. */
-			if (*(m->m_ext.ext_cnt) == 0)
-				*(m->m_ext.ext_cnt) = 1;
-			uma_zfree(zone_pack, m);
-			return;		/* Job done. */
-		case EXT_CLUSTER:
-			uma_zfree(zone_clust, m->m_ext.ext_buf);
-			break;
-		case EXT_JUMBOP:
-			uma_zfree(zone_jumbop, m->m_ext.ext_buf);
-			break;
-		case EXT_JUMBO9:
-			uma_zfree(zone_jumbo9, m->m_ext.ext_buf);
-			break;
-		case EXT_JUMBO16:
-			uma_zfree(zone_jumbo16, m->m_ext.ext_buf);
-			break;
-		case EXT_NET_DRV:
-		case EXT_MOD_TYPE:
-		case EXT_DISPOSABLE:
-			*(m->m_ext.ext_cnt) = 0;
-			uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *,
-				m->m_ext.ext_cnt));
-			/* FALLTHROUGH */
-		case EXT_EXTREF:
-			KASSERT(m->m_ext.ext_free != NULL,
-				("%s: ext_free not set", __func__));
-			(*(m->m_ext.ext_free))(m, m->m_ext.ext_arg1,
-			    m->m_ext.ext_arg2);
-			break;
-		default:
-			KASSERT(m->m_ext.ext_type == 0,
-				("%s: unknown ext_type", __func__));
-		}
+		m->m_data = m->m_pktdat;
+		bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
+#ifdef MAC
+		/* If the label init fails, fail the alloc */
+		error = mac_mbuf_init(m, how);
+		if (error)
+			return (error);
+#endif
 	}
 
-	if (freembuf)
-		uma_zfree(zone_mbuf, m);
+	return (0);
 }
 
 /*
diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c
--- a/sys/kern/kern_mbuf.c
+++ b/sys/kern/kern_mbuf.c
@@ -44,8 +44,6 @@
 #include <sys/smp.h>
 #include <sys/sysctl.h>
 
-#include <security/mac/mac_framework.h>
-
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_kern.h>
@@ -99,6 +97,17 @@
  *
  */
 
+/*
+ * Zones from which we allocate.
+ */
+static uma_zone_t	zone_mbuf;
+static uma_zone_t	zone_clust;
+static uma_zone_t	zone_pack;
+static uma_zone_t	zone_jumbop;
+static uma_zone_t	zone_jumbo9;
+static uma_zone_t	zone_jumbo16;
+static uma_zone_t	zone_ext_refcnt;
+
 int nmbufs;			/* limits number of mbufs */
 int nmbclusters;		/* limits number of mbuf clusters */
 int nmbjumbop;			/* limits number of page size jumbo clusters */
@@ -111,6 +120,15 @@
     "Maximum real memory allocatable to various mbuf types");
 
 /*
+ * Argument structure passed to UMA routines during mbuf and packet
+ * allocations.
+ */
+struct mb_args {
+	int	flags;	/* Flags for mbuf being allocated */
+	short	type;	/* Type of mbuf being allocated */
+};
+
+/*
  * tunable_mbinit() has to be run before any mbuf allocations are done.
  */
 static void
@@ -263,34 +281,25 @@
     "Maximum number of mbufs allowed");
 
 /*
- * Zones from which we allocate.
- */
-uma_zone_t	zone_mbuf;
-uma_zone_t	zone_clust;
-uma_zone_t	zone_pack;
-uma_zone_t	zone_jumbop;
-uma_zone_t	zone_jumbo9;
-uma_zone_t	zone_jumbo16;
-uma_zone_t	zone_ext_refcnt;
-
-/*
  * Callout to assist us in freeing mbufs.
  */
 static struct callout	mb_reclaim_callout;
 static struct mtx	mb_reclaim_callout_mtx;
 
 /*
  * Local prototypes.
+ * XXX: two are exported for sake of cxgbe(4)
  */
+uma_zone_t	m_getzone(int);
+void		m_cljset(struct mbuf *, void *, int);
 static int	mb_ctor_mbuf(void *, int, void *, int);
 static int	mb_ctor_clust(void *, int, void *, int);
 static int	mb_ctor_pack(void *, int, void *, int);
 static void	mb_dtor_mbuf(void *, int, void *);
 static void	mb_dtor_clust(void *, int, void *);
 static void	mb_dtor_pack(void *, int, void *);
 static int	mb_zinit_pack(void *, int, int);
 static void	mb_zfini_pack(void *, int);
-
 static void	mb_reclaim(void *);
 static void    *mbuf_jumbo_alloc(uma_zone_t, vm_size_t, uint8_t *, int);
 static void	mb_maxaction(uma_zone_t);
@@ -449,7 +458,7 @@
 	m = (struct mbuf *)mem;
 	flags = args->flags;
 
-	error = m_init(m, NULL, size, how, type, flags);
+	error = m_init(m, how, type, flags);
 
 	return (error);
 }
@@ -649,33 +658,15 @@
 	trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
 #endif
 
-	error = m_init(m, NULL, size, how, type, flags);
+	error = m_init(m, how, type, flags);
 
 	/* m_ext is already initialized. */
 	m->m_data = m->m_ext.ext_buf;
  	m->m_flags = (flags | M_EXT);
 
 	return (error);
 }
 
-int
-m_pkthdr_init(struct mbuf *m, int how)
-{
-#ifdef MAC
-	int error;
-#endif
-	m->m_data = m->m_pktdat;
-	bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
-#ifdef MAC
-	/* If the label init fails, fail the alloc */
-	error = mac_mbuf_init(m, how);
-	if (error)
-		return (error);
-#endif
-
-	return (0);
-}
-
 /*
  * This is the protocol drain routine.
  *
@@ -755,3 +746,437 @@
 
 	mtx_unlock(&mb_reclaim_callout_mtx);
 }
+
+/*
+ * Select zone by size.
+ */
+uma_zone_t
+m_getzone(int size)
+{
+	uma_zone_t zone;
+
+	switch (size) {
+	case MCLBYTES:
+		zone = zone_clust;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case MJUMPAGESIZE:
+		zone = zone_jumbop;
+		break;
+#endif
+	case MJUM9BYTES:
+		zone = zone_jumbo9;
+		break;
+	case MJUM16BYTES:
+		zone = zone_jumbo16;
+		break;
+	default:
+		panic("%s: invalid cluster size %d", __func__, size);
+	}
+
+	return (zone);
+}
+
+/*
+ * Clean up after mbufs with M_EXT storage attached to them if the
+ * reference count hits 1.
+ */
+static void
+mb_free_ext(struct mbuf *m)
+{
+	int freembuf;
+
+	KASSERT(m->m_flags & M_EXT, ("%s: M_EXT not set on %p", __func__, m));
+
+	/*
+	 * Check if the header is embedded in the cluster.
+	 */
+	freembuf = (m->m_flags & M_NOFREE) ? 0 : 1;
+
+	switch (m->m_ext.ext_type) {
+	case EXT_SFBUF:
+		sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
+		break;
+	case EXT_SFBUF_NOCACHE:
+		sf_ext_free_nocache(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
+		break;
+	default:
+		KASSERT(m->m_ext.ext_cnt != NULL,
+		    ("%s: no refcounting pointer on %p", __func__, m));
+		/* 
+		 * Free attached storage if this mbuf is the only
+		 * reference to it.
+		 */
+		if (*(m->m_ext.ext_cnt) != 1) {
+			if (atomic_fetchadd_int(m->m_ext.ext_cnt, -1) != 1)
+				break;
+		}
+
+		switch (m->m_ext.ext_type) {
+		case EXT_PACKET:	/* The packet zone is special. */
+			if (*(m->m_ext.ext_cnt) == 0)
+				*(m->m_ext.ext_cnt) = 1;
+			uma_zfree(zone_pack, m);
+			return;		/* Job done. */
+		case EXT_CLUSTER:
+			uma_zfree(zone_clust, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBOP:
+			uma_zfree(zone_jumbop, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBO9:
+			uma_zfree(zone_jumbo9, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBO16:
+			uma_zfree(zone_jumbo16, m->m_ext.ext_buf);
+			break;
+		case EXT_NET_DRV:
+		case EXT_MOD_TYPE:
+		case EXT_DISPOSABLE:
+			*(m->m_ext.ext_cnt) = 0;
+			uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *,
+				m->m_ext.ext_cnt));
+			/* FALLTHROUGH */
+		case EXT_EXTREF:
+			KASSERT(m->m_ext.ext_free != NULL,
+				("%s: ext_free not set", __func__));
+			(*(m->m_ext.ext_free))(m, m->m_ext.ext_arg1,
+			    m->m_ext.ext_arg2);
+			break;
+		default:
+			KASSERT(m->m_ext.ext_type == 0,
+				("%s: unknown ext_type", __func__));
+		}
+	}
+
+	if (freembuf)
+		uma_zfree(zone_mbuf, m);
+}
+
+/*
+ * Official mbuf(9) allocation KPI for stack and drivers:
+ *
+ * m_get()	- a single mbuf without any attachments.
+ * m_gethdr()	- a single mbuf initialized as M_PKTHDR.
+ * m_getcl()	- an mbuf + 2k cluster.
+ * m_clget()	- attach cluster to already allocated mbuf.
+ * m_cljget()	- attach jumbo cluster to already allocated mbuf.
+ * m_get2()	- allocate minimum mbuf that would fit size argument.
+ * m_getm2()	- allocate a chain of mbufs/clusters.
+ * m_extadd()	- attach external cluster to mbuf.
+ *
+ * m_free()	- free single mbuf with its tags and ext, returns next mbuf.
+ * m_freem()	- free chain of mbufs.
+ */
+
+struct mbuf *
+m_get(int how, short type)
+{
+	struct mb_args args;
+
+	args.flags = 0;
+	args.type = type;
+	return (uma_zalloc_arg(zone_mbuf, &args, how));
+}
+
+struct mbuf *
+m_gethdr(int how, short type)
+{
+	struct mb_args args;
+
+	args.flags = M_PKTHDR;
+	args.type = type;
+	return (uma_zalloc_arg(zone_mbuf, &args, how));
+}
+
+struct mbuf *
+m_getcl(int how, short type, int flags)
+{
+	struct mb_args args;
+
+	args.flags = flags;
+	args.type = type;
+	return (uma_zalloc_arg(zone_pack, &args, how));
+}
+
+int
+m_clget(struct mbuf *m, int how)
+{
+
+	KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
+	    __func__, m));
+	m->m_ext.ext_buf = (char *)NULL;
+	uma_zalloc_arg(zone_clust, m, how);
+	/*
+	 * On a cluster allocation failure, drain the packet zone and retry,
+	 * we might be able to loosen a few clusters up on the drain.
+	 */
+	if ((how & M_NOWAIT) && (m->m_ext.ext_buf == NULL)) {
+		zone_drain(zone_pack);
+		uma_zalloc_arg(zone_clust, m, how);
+	}
+	return (m->m_flags & M_EXT);
+}
+
+/*
+ * m_cljget() is different from m_clget() as it can allocate clusters without
+ * attaching them to an mbuf.  In that case the return value is the pointer
+ * to the cluster of the requested size.  If an mbuf was specified, it gets
+ * the cluster attached to it and the return value can be safely ignored.
+ * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
+ */
+void *
+m_cljget(struct mbuf *m, int how, int size)
+{
+	uma_zone_t zone;
+
+	if (m != NULL) {
+		KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
+		    __func__, m));
+		m->m_ext.ext_buf = NULL;
+	}
+
+	zone = m_getzone(size);
+	return (uma_zalloc_arg(zone, m, how));
+}
+
+void
+m_cljset(struct mbuf *m, void *cl, int type)
+{
+	uma_zone_t zone;
+	int size;
+
+	switch (type) {
+	case EXT_CLUSTER:
+		size = MCLBYTES;
+		zone = zone_clust;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case EXT_JUMBOP:
+		size = MJUMPAGESIZE;
+		zone = zone_jumbop;
+		break;
+#endif
+	case EXT_JUMBO9:
+		size = MJUM9BYTES;
+		zone = zone_jumbo9;
+		break;
+	case EXT_JUMBO16:
+		size = MJUM16BYTES;
+		zone = zone_jumbo16;
+		break;
+	default:
+		panic("%s: unknown cluster type %d", __func__, type);
+		break;
+	}
+
+	m->m_data = m->m_ext.ext_buf = cl;
+	m->m_ext.ext_free = m->m_ext.ext_arg1 = m->m_ext.ext_arg2 = NULL;
+	m->m_ext.ext_size = size;
+	m->m_ext.ext_type = type;
+	m->m_ext.ext_flags = 0;
+	m->m_ext.ext_cnt = uma_find_refcnt(zone, cl);
+	m->m_flags |= M_EXT;
+
+}
+
+/*
+ * m_get2() allocates minimum mbuf that would fit "size" argument.
+ */
+struct mbuf *
+m_get2(int size, int how, short type, int flags)
+{
+	struct mb_args args;
+	struct mbuf *m, *n;
+
+	args.flags = flags;
+	args.type = type;
+
+	if (size <= MHLEN || (size <= MLEN && (flags & M_PKTHDR) == 0))
+		return (uma_zalloc_arg(zone_mbuf, &args, how));
+	if (size <= MCLBYTES)
+		return (uma_zalloc_arg(zone_pack, &args, how));
+
+	if (size > MJUMPAGESIZE)
+		return (NULL);
+
+	m = uma_zalloc_arg(zone_mbuf, &args, how);
+	if (m == NULL)
+		return (NULL);
+
+	n = uma_zalloc_arg(zone_jumbop, m, how);
+	if (n == NULL) {
+		uma_zfree(zone_mbuf, m);
+		return (NULL);
+	}
+
+	return (m);
+}
+
+/*
+ * m_getjcl() returns an mbuf with a cluster of the specified size attached.
+ * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
+ */
+struct mbuf *
+m_getjcl(int how, short type, int flags, int size)
+{
+	struct mb_args args;
+	struct mbuf *m, *n;
+	uma_zone_t zone;
+
+	if (size == MCLBYTES)
+		return m_getcl(how, type, flags);
+
+	args.flags = flags;
+	args.type = type;
+
+	m = uma_zalloc_arg(zone_mbuf, &args, how);
+	if (m == NULL)
+		return (NULL);
+
+	zone = m_getzone(size);
+	n = uma_zalloc_arg(zone, m, how);
+	if (n == NULL) {
+		uma_zfree(zone_mbuf, m);
+		return (NULL);
+	}
+	return (m);
+}
+
+/*
+ * Allocate a given length worth of mbufs and/or clusters (whatever fits
+ * best) and return a pointer to the top of the allocated chain.  If an
+ * existing mbuf chain is provided, then we will append the new chain
+ * to the existing one but still return the top of the newly allocated
+ * chain.
+ */
+struct mbuf *
+m_getm2(struct mbuf *m, int len, int how, short type, int flags)
+{
+	struct mbuf *mb, *nm = NULL, *mtail = NULL;
+
+	KASSERT(len >= 0, ("%s: len is < 0", __func__));
+
+	/* Validate flags. */
+	flags &= (M_PKTHDR | M_EOR);
+
+	/* Packet header mbuf must be first in chain. */
+	if ((flags & M_PKTHDR) && m != NULL)
+		flags &= ~M_PKTHDR;
+
+	/* Loop and append maximum sized mbufs to the chain tail. */
+	while (len > 0) {
+		if (len > MCLBYTES)
+			mb = m_getjcl(how, type, (flags & M_PKTHDR),
+			    MJUMPAGESIZE);
+		else if (len >= MINCLSIZE)
+			mb = m_getcl(how, type, (flags & M_PKTHDR));
+		else if (flags & M_PKTHDR)
+			mb = m_gethdr(how, type);
+		else
+			mb = m_get(how, type);
+
+		/* Fail the whole operation if one mbuf can't be allocated. */
+		if (mb == NULL) {
+			if (nm != NULL)
+				m_freem(nm);
+			return (NULL);
+		}
+
+		/* Book keeping. */
+		len -= M_SIZE(mb);
+		if (mtail != NULL)
+			mtail->m_next = mb;
+		else
+			nm = mb;
+		mtail = mb;
+		flags &= ~M_PKTHDR;	/* Only valid on the first mbuf. */
+	}
+	if (flags & M_EOR)
+		mtail->m_flags |= M_EOR;  /* Only valid on the last mbuf. */
+
+	/* If mbuf was supplied, append new chain to the end of it. */
+	if (m != NULL) {
+		for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next)
+			;
+		mtail->m_next = nm;
+		mtail->m_flags &= ~M_EOR;
+	} else
+		m = nm;
+
+	return (m);
+}
+
+/*-
+ * Configure a provided mbuf to refer to the provided external storage
+ * buffer and setup a reference count for said buffer.  If the setting
+ * up of the reference count fails, the M_EXT bit will not be set.  If
+ * successfull, the M_EXT bit is set in the mbuf's flags.
+ *
+ * Arguments:
+ *    mb     The existing mbuf to which to attach the provided buffer.
+ *    buf    The address of the provided external storage buffer.
+ *    size   The size of the provided buffer.
+ *    freef  A pointer to a routine that is responsible for freeing the
+ *           provided external storage buffer.
+ *    args   A pointer to an argument structure (of any type) to be passed
+ *           to the provided freef routine (may be NULL).
+ *    flags  Any other flags to be passed to the provided mbuf.
+ *    type   The type that the external storage buffer should be
+ *           labeled with.
+ *
+ * Returns:
+ *    Nothing.
+ */
+int
+m_extadd(struct mbuf *mb, caddr_t buf, u_int size,
+    void (*freef)(struct mbuf *, void *, void *), void *arg1, void *arg2,
+    int flags, int type, int wait)
+{
+	KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__));
+
+	if (type != EXT_EXTREF)
+		mb->m_ext.ext_cnt = uma_zalloc(zone_ext_refcnt, wait);
+
+	if (mb->m_ext.ext_cnt == NULL)
+		return (ENOMEM);
+
+	*(mb->m_ext.ext_cnt) = 1;
+	mb->m_flags |= (M_EXT | flags);
+	mb->m_ext.ext_buf = buf;
+	mb->m_data = mb->m_ext.ext_buf;
+	mb->m_ext.ext_size = size;
+	mb->m_ext.ext_free = freef;
+	mb->m_ext.ext_arg1 = arg1;
+	mb->m_ext.ext_arg2 = arg2;
+	mb->m_ext.ext_type = type;
+	mb->m_ext.ext_flags = 0;
+
+	return (0);
+}
+
+struct mbuf *
+m_free(struct mbuf *m)
+{
+	struct mbuf *n = m->m_next;
+
+	if ((m->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
+		m_tag_delete_chain(m, NULL);
+	if (m->m_flags & M_EXT)
+		mb_free_ext(m);
+	else if ((m->m_flags & M_NOFREE) == 0)
+		uma_zfree(zone_mbuf, m);
+	return (n);
+}
+
+/*
+ * Free an entire chain of mbufs and associated external buffers, if
+ * applicable.
+ */
+void
+m_freem(struct mbuf *mb)
+{
+
+	while (mb != NULL)
+		mb = m_free(mb);
+}
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -122,7 +122,7 @@
 	m->m_ext.ext_free = NULL;
 	if (GET_MBUF_REFCNT(m) == 0)
 		SET_MBUF_REFCNT(m, 1);
-	uma_zfree(zone_pack, m);
+	m_free(m);
 }
 
 static inline struct mbuf *
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -70,6 +70,12 @@
 #include "common/t4_msg.h"
 #include "t4_mp_ring.h"
 
+/*
+ * Internal mbuf(9) knowledge.
+ */
+uma_zone_t      m_getzone(int);
+void		m_cljset(struct mbuf *m, void *cl, int type);
+
 #ifdef T4_PKT_TIMESTAMP
 #define RX_COPY_THRESHOLD (MINCLSIZE - 8)
 #else
@@ -1570,7 +1576,7 @@
 		MPASS(clm != NULL);
 		m = (struct mbuf *)(sd->cl + sd->nmbuf * MSIZE);
 		/* No bzero required */
-		if (m_init(m, NULL, 0, M_NOWAIT, MT_DATA,
+		if (m_init(m, M_NOWAIT, MT_DATA,
 		    fr_offset == 0 ? M_PKTHDR | M_NOFREE : M_NOFREE))
 			return (NULL);
 		fl->mbuf_inlined++;
diff --git a/sys/dev/cxgbe/t4_netmap.c b/sys/dev/cxgbe/t4_netmap.c
--- a/sys/dev/cxgbe/t4_netmap.c
+++ b/sys/dev/cxgbe/t4_netmap.c
@@ -36,6 +36,7 @@
 #include <sys/bus.h>
 #include <sys/eventhandler.h>
 #include <sys/lock.h>
+#include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/selinfo.h>
diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c
--- a/sys/dev/cxgb/cxgb_sge.c
+++ b/sys/dev/cxgb/cxgb_sge.c
@@ -77,6 +77,12 @@
 #include <cxgb_include.h>
 #include <sys/mvec.h>
 
+/*
+ * Internal mbuf(9) knowledge.
+ */
+uma_zone_t	m_getzone(int);
+void		m_cljset(struct mbuf *m, void *cl, int type);
+
 int	txq_fills = 0;
 int	multiq_tx_enable = 1;
 
@@ -713,7 +719,7 @@
 		 * We allocate an uninitialized mbuf + cluster, mbuf is
 		 * initialized after rx.
 		 */
-		if (q->zone == zone_pack) {
+		if (q->type == EXT_CLUSTER) {
 			if ((m = m_getcl(M_NOWAIT, MT_NOINIT, M_PKTHDR)) == NULL)
 				break;
 			cl = m->m_ext.ext_buf;			
@@ -738,7 +744,7 @@
 		    cl, q->buf_size, refill_fl_cb, &cb_arg, 0);
 		
 		if (err != 0 || cb_arg.error) {
-			if (q->zone != zone_pack)
+			if (q->type != EXT_CLUSTER)
 				uma_zfree(q->zone, cl);
 			m_free(m);
 			goto done;
@@ -794,14 +800,12 @@
 		if (d->flags & RX_SW_DESC_INUSE) {
 			bus_dmamap_unload(q->entry_tag, d->map);
 			bus_dmamap_destroy(q->entry_tag, d->map);
-			if (q->zone == zone_pack) {
-				m_init(d->m, zone_pack, MCLBYTES,
-				    M_NOWAIT, MT_DATA, M_EXT);
-				uma_zfree(zone_pack, d->m);
+			if (q->type == EXT_CLUSTER) {
+				m_init(d->m, M_NOWAIT, MT_DATA, M_EXT);
+				uma_zfree(q->zone, d->m);
 			} else {
-				m_init(d->m, zone_mbuf, MLEN,
-				    M_NOWAIT, MT_DATA, 0);
-				uma_zfree(zone_mbuf, d->m);
+				m_init(d->m, M_NOWAIT, MT_DATA, 0);
+				m_free(d->m);
 				uma_zfree(q->zone, d->rxsd_cl);
 			}			
 		}
@@ -2510,24 +2514,12 @@
 	    flits_to_desc(sgl_len(TX_MAX_SEGS + 1) + 3);
 
 	q->fl[0].buf_size = MCLBYTES;
-	q->fl[0].zone = zone_pack;
-	q->fl[0].type = EXT_PACKET;
+	q->fl[0].zone = m_getzone(q->fl[0].buf_size);
+	q->fl[0].type = m_gettype(q->fl[0].buf_size);
 
-	if (p->jumbo_buf_size ==  MJUM16BYTES) {
-		q->fl[1].zone = zone_jumbo16;
-		q->fl[1].type = EXT_JUMBO16;
-	} else if (p->jumbo_buf_size ==  MJUM9BYTES) {
-		q->fl[1].zone = zone_jumbo9;
-		q->fl[1].type = EXT_JUMBO9;		
-	} else if (p->jumbo_buf_size ==  MJUMPAGESIZE) {
-		q->fl[1].zone = zone_jumbop;
-		q->fl[1].type = EXT_JUMBOP;
-	} else {
-		KASSERT(0, ("can't deal with jumbo_buf_size %d.", p->jumbo_buf_size));
-		ret = EDOOFUS;
-		goto err;
-	}
 	q->fl[1].buf_size = p->jumbo_buf_size;
+	q->fl[1].zone = m_getzone(q->fl[1].buf_size);
+	q->fl[1].type = m_gettype(q->fl[1].buf_size);
 
 	/* Allocate and setup the lro_ctrl structure */
 	q->lro.enabled = !!(pi->ifp->if_capenable & IFCAP_LRO);
@@ -2725,8 +2717,8 @@
 		if ((sopeop == RSPQ_SOP_EOP) ||
 		    (sopeop == RSPQ_SOP))
 			flags |= M_PKTHDR;
-		m_init(m, fl->zone, fl->buf_size, M_NOWAIT, MT_DATA, flags);
-		if (fl->zone == zone_pack) {
+		m_init(m, M_NOWAIT, MT_DATA, flags);
+		if (fl->type == EXT_CLUSTER) {
 			/*
 			 * restore clobbered data pointer
 			 */
diff --git a/sys/dev/cxgb/cxgb_adapter.h b/sys/dev/cxgb/cxgb_adapter.h
--- a/sys/dev/cxgb/cxgb_adapter.h
+++ b/sys/dev/cxgb/cxgb_adapter.h
@@ -42,6 +42,7 @@
 #include <sys/condvar.h>
 #include <sys/buf_ring.h>
 #include <sys/taskqueue.h>
+#include <vm/uma.h>
 
 #include <net/ethernet.h>
 #include <net/if.h>

_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-transport
To unsubscribe, send any mail to "[email protected]"

Reply via email to