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