cvs commit: src/sys/conf options src/sys/netinet ip_output.c

Mike Silbersack silby at silby.com
Thu Mar 27 07:40:42 PST 2003


Ok, I think I have m_defrag in a working state, please review.

Changes from last time:

- It supports infinitely long chains.
- It has a "goal" argument which is supposed to be a hint to tell m_defrag
how long the chain can be.  It is currently ignored; someone may want to
honor this later for optimization purposes.
- I fixed up the error case in if_xl, it only runs if needed now

At the top of the if_loop and if_xl patches are debugging code I used to
make it was working right, they're certainly not going in.

m_defrag should be totally free of debug code.

Dig in!

Mike "Silby" Silbersack
-------------- next part --------------
diff -u -r /usr/src/sys.old/kern/uipc_mbuf.c /usr/src/sys/kern/uipc_mbuf.c
--- /usr/src/sys.old/kern/uipc_mbuf.c	Tue Mar 25 19:51:44 2003
+++ /usr/src/sys/kern/uipc_mbuf.c	Thu Mar 27 01:32:36 2003
@@ -52,6 +52,7 @@
 int	max_protohdr;
 int	max_hdr;
 int	max_datalen;
+int	m_defragcount;
 
 /*
  * sysctl(8) exported objects
@@ -64,6 +65,8 @@
 SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RW, &max_hdr, 0, "");
 SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW,
 	   &max_datalen, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragcount, CTLFLAG_RW,
+	   &m_defragcount, 0, "");
 
 /*
  * "Move" mbuf pkthdr from "from" to "to".
@@ -777,4 +780,66 @@
 	if (last != NULL)
 		*last = m;
 	return (len);
+}
+
+/*
+ * Defragment a mbuf chain, returning a new mbuf chain which is
+ * comprised of some chain =< "goal".  Return NULL if mbuf
+ * allocation fails, rather than returning the still fragmented
+ * chain.  If a non-packet header is passed in, the original
+ * mbuf (chain?) will be returned unharmed.
+ *
+ */
+struct mbuf *
+m_defrag(struct mbuf *m0, int how, int goal)
+{
+	struct mbuf	*m_new = NULL, *m_final = NULL;
+	int		progress = 0, length;
+
+	if (!(m0->m_flags & M_PKTHDR))
+		return (m0);
+
+	m_final = m_gethdr(how, MT_DATA);
+
+	if (m_final == NULL)
+		goto nospace;
+
+	if (m_dup_pkthdr(m_final, m0, how) == NULL)
+		goto nospace;
+
+	m_new = m_final;
+
+	while (progress < m0->m_pkthdr.len) {
+		length = m0->m_pkthdr.len - progress;
+		if (length > MCLBYTES)
+			length = MCLBYTES;
+
+		if (m_new == NULL)
+			m_new = m_get(how, MT_DATA);
+
+		if (length > MHLEN) {
+			MCLGET(m_new, how);
+			if ((m_new->m_flags & M_EXT) == 0)
+				goto nospace;
+		}
+
+		m_copydata(m0, progress, length, mtod(m_new, caddr_t));
+		progress += length;
+		m_new->m_len = length;
+		if (m_new != m_final)
+			m_cat(m_final, m_new);
+		m_new = NULL;
+	}
+	m_freem(m0);
+	m0 = m_final;
+	m_defragcount++;
+	return (m0);
+nospace:
+	if (m0)
+		m_freem(m0);
+	if (m_new)
+		m_free(m_new);
+	if (m_final)
+		m_freem(m_final);
+	return (NULL);
 }
diff -u -r /usr/src/sys.old/net/if_loop.c /usr/src/sys/net/if_loop.c
--- /usr/src/sys.old/net/if_loop.c	Tue Mar 25 19:51:02 2003
+++ /usr/src/sys/net/if_loop.c	Thu Mar 27 01:37:45 2003
@@ -192,6 +192,27 @@
 	struct sockaddr *dst;
 	register struct rtentry *rt;
 {
+	struct mbuf	*m_temp;
+	int	before = 0, after = 0;
+	int	lbefore = 0, lafter = 0;
+
+
+        for (m_temp = m; m_temp != NULL; m_temp = m_temp->m_next) {
+                lbefore += m_temp->m_len;
+                before++;
+        }
+ 
+        if (before > 20)
+                m = m_defrag(m, M_DONTWAIT, 1);
+ 
+        for (m_temp = m; m_temp != NULL; m_temp = m_temp->m_next) { 
+                lafter += m_temp->m_len;
+                after++;
+        }
+
+        if (before != after)
+                printf("before: %i (%i) after: %i (%i)\n", before, lbefore, after, lafter);
+
 	if ((m->m_flags & M_PKTHDR) == 0)
 		panic("looutput no HDR");
 
diff -u -r /usr/src/sys.old/pci/if_xl.c /usr/src/sys/pci/if_xl.c
--- /usr/src/sys.old/pci/if_xl.c	Tue Mar 25 19:50:52 2003
+++ /usr/src/sys/pci/if_xl.c	Thu Mar 27 01:01:02 2003
@@ -2412,9 +2412,27 @@
 	struct xl_chain		*c;
 	struct mbuf		*m_head;
 {
-	struct xl_frag		*f = NULL;
 	int			error;
-	u_int32_t		baddr, status;
+	u_int32_t		status;
+	struct mbuf		*m_temp;
+	int			lbefore = 0, lafter = 0;
+	int			before = 0, after = 0;
+
+	for (m_temp = m_head; m_temp != NULL; m_temp = m_temp->m_next) {
+		lbefore += m_temp->m_len;
+		before++;
+	}
+
+	if (before > 5)
+		m_head = m_defrag(m_head, M_DONTWAIT, 1);
+
+	for (m_temp = m_head; m_temp != NULL; m_temp = m_temp->m_next) {
+		lafter += m_temp->m_len;
+		after++;
+	}
+
+	if (before != after)
+		printf("before: %i (%i) after: %i (%i)\n", before, lbefore, after, lafter);
 
 	/*
  	 * Start packing the mbufs in this chain into
@@ -2439,35 +2457,21 @@
 	 * and would waste cycles.
 	 */
 	if (error) {
-		struct mbuf		*m_new;
+		m_head = m_defrag(m_head, M_DONTWAIT, XL_MAXFRAGS);
 
-		m_new = m_head->m_pkthdr.len > MHLEN ?
-		    m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR) :
-		    m_gethdr(M_DONTWAIT, MT_DATA);
-		if (m_new == NULL) {
-			m_freem(m_head);
+		if (m_head == NULL) {
 			printf("xl%d: no memory for tx list\n", sc->xl_unit);
 			return(1);
 		}
-		m_copydata(m_head, 0, m_head->m_pkthdr.len,	
-					mtod(m_new, caddr_t));
-		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
-		m_freem(m_head);
-		m_head = m_new;
-		f = &c->xl_ptr->xl_frag[0];
-		error = bus_dmamap_load(sc->xl_mtag, c->xl_map,
-		    mtod(m_new, void *), MCLBYTES, xl_dma_map_addr,
-		    &baddr, 0);
+
+		error = bus_dmamap_load_mbuf(sc->xl_mtag, c->xl_map,
+			m_head, xl_dma_map_txbuf, c->xl_ptr, 0);
 		if (error) {
-			m_freem(m_new);
+			m_freem(m_head);
 			printf("xl%d: can't map mbuf (error %d)\n",
 			    sc->xl_unit, error);
 			return(1);
 		}
-		f->xl_addr = htole32(baddr);
-		f->xl_len = htole32(m_new->m_len | XL_LAST_FRAG);
-		c->xl_ptr->xl_status = htole32(m_new->m_len);
-		c->xl_ptr->xl_next = 0;
 	}
 
 	if (sc->xl_type == XL_TYPE_905B) {
diff -u -r /usr/src/sys.old/pci/if_xlreg.h /usr/src/sys/pci/if_xlreg.h
--- /usr/src/sys.old/pci/if_xlreg.h	Tue Mar 25 19:50:52 2003
+++ /usr/src/sys/pci/if_xlreg.h	Tue Mar 25 21:28:53 2003
@@ -420,7 +420,7 @@
 
 #define XL_LAST_FRAG		0x80000000
 
-#define XL_MAXFRAGS		63
+#define XL_MAXFRAGS		10
 #define XL_RX_LIST_CNT		128
 #define XL_TX_LIST_CNT		256
 #define XL_RX_LIST_SZ		XL_RX_LIST_CNT * sizeof(struct xl_list_onefrag)
diff -u -r /usr/src/sys.old/sys/mbuf.h /usr/src/sys/sys/mbuf.h
--- /usr/src/sys.old/sys/mbuf.h	Tue Mar 25 19:50:46 2003
+++ /usr/src/sys/sys/mbuf.h	Wed Mar 26 19:59:26 2003
@@ -430,6 +430,7 @@
 struct	mbuf	*m_copym(struct mbuf *, int, int, int);
 struct	mbuf	*m_copypacket(struct mbuf *, int);
 void		 m_copy_pkthdr(struct mbuf *, struct mbuf *);
+struct	mbuf	*m_defrag(struct mbuf *, int, int);
 struct	mbuf	*m_devget(char *, int, int, struct ifnet *,
 		    void (*)(char *, caddr_t, u_int));
 struct	mbuf	*m_dup(struct mbuf *, int);


More information about the cvs-src mailing list