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

Mike Silbersack silby at silby.com
Wed Mar 26 17:52:46 PST 2003


On Tue, 25 Mar 2003, Doug Ambrisko wrote:

> | I think that we'll end up being even better off by just making a
> | m_defragment function, thereby reducing code duplication even more.  I'll
> | make sure to test any such function more than I tested the MBUF_FRAG_TEST
> | code, however. :)
>
> Yes, I was thinking that as well.

Ok, here's my attempt at a m_defragment function.  It seems to work well
here, although I have only tested it with the if_xl driver.  Could you
guys give it a quick lookover to see if it has any bugs?  I'll add the
ability to copy mbuf chains longer than MCLBYTES once I know all the
packet header handling / etc is correct.

Also note that the patch contains my changes to if_xl, which are mostly
debugging code.  You can ignore most of that.  One change I _will_ make to
if_xl, however, is to walk the chain and find out its length _before_ we
do any busdma calls; this moves the defragmentation occur earlier, thereby
avoiding the need for a complex error recovery case.  I suspect we'll want
to do the same in the other network drivers.

Thanks,

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	Wed Mar 26 11:42:58 2003
@@ -778,3 +778,52 @@
 		*last = m;
 	return (len);
 }
+
+/*
+ * Defragment a mbuf chain, returning a new mbuf chain which is
+ * comprised of as few mbufs and clusters as possible.  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.
+ *
+ * FIXME: Does not handle data sizes > MCLBYTES
+ */
+struct mbuf *
+m_defragment(struct mbuf *m0, int how)
+{
+	struct mbuf	*m_new = NULL;
+
+	if (!(m0->m_flags & M_PKTHDR))
+		return (m0);
+
+	if (m0->m_pkthdr.len > MCLBYTES)
+		goto nospace;
+
+	m_new = m_gethdr(how, MT_DATA);
+
+	if (m_new == NULL)
+		goto nospace;
+
+	if (!m_dup_pkthdr(m_new, m0, how))
+		goto nospace;
+	m_new->m_len = m0->m_len;
+
+	if (m0->m_pkthdr.len > MHLEN) {
+		MCLGET(m_new, how);
+		if ((m_new->m_flags & M_EXT) == 0)
+			goto nospace;
+	}
+
+	m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m_new, caddr_t));
+	m_new->m_len = m0->m_pkthdr.len;
+	m_freem(m0);
+	m0 = m_new;
+	return (m0);
+nospace:
+	if (m0)
+		m_freem(m0);
+	if (m_new)
+		m_free(m_new);
+	return (NULL);
+
+}
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	Wed Mar 26 01:55:41 2003
@@ -2412,9 +2412,33 @@
 	struct xl_chain		*c;
 	struct mbuf		*m_head;
 {
-	struct xl_frag		*f = NULL;
-	int			error;
-	u_int32_t		baddr, status;
+	struct mbuf		*m_new;
+	int			error, chainlength = 0, after = 0;
+	int			lbefore = 0, lafter = 0;
+	u_int32_t		status;
+	
+	for (m_new = m_head; m_new != NULL; m_new = m_new->m_next) {
+		lbefore += m_new->m_len;
+		chainlength++;
+	}
+
+	if (chainlength > XL_MAXFRAGS) {
+		printf("Starting defragmentation\n");
+		m_head = m_defragment(m_head, M_DONTWAIT);
+
+		if (m_head == NULL) {
+			printf("xl%d: no memory for tx list\n", sc->xl_unit);
+			return (1);
+		}
+
+		for (m_new = m_head; m_new != NULL; m_new = m_new->m_next) {
+			lafter += m_new->m_len;
+			after++;
+		}
+
+		printf("Before: %i After: %i\n", chainlength, after);
+		printf("Lbefore: %i Lafter: %i\n", lbefore, lafter);
+	}
 
 	/*
  	 * Start packing the mbufs in this chain into
@@ -2428,46 +2452,6 @@
 		m_freem(m_head);
 		printf("xl%d: can't map mbuf (error %d)\n", sc->xl_unit, error);
 		return(1);
-	}
-
-	/*
-	 * Handle special case: we used up all 63 fragments,
-	 * but we have more mbufs left in the chain. Copy the
-	 * data into an mbuf cluster. Note that we don't
-	 * bother clearing the values in the other fragment
-	 * pointers/counters; it wouldn't gain us anything,
-	 * and would waste cycles.
-	 */
-	if (error) {
-		struct mbuf		*m_new;
-
-		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);
-			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);
-		if (error) {
-			m_freem(m_new);
-			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 01:58:17 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_defragment(struct mbuf *, 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