* Defragment an mbuf chain, returning at most maxfrags separate * mbufs+clusters. If this is not possible NULL is returned and * the original mbuf chain is left in its present (potentially * modified) state. We use two techniques: collapsing consecutive * mbufs and replacing consecutive mbufs by a cluster. * * NB: this should really be named m_defrag but that name is taken */
| 1472 | * NB: this should really be named m_defrag but that name is taken |
| 1473 | */ |
| 1474 | struct mbuf * |
| 1475 | m_collapse(struct mbuf *m0, int how, int maxfrags) |
| 1476 | { |
| 1477 | struct mbuf *m, *n, *n2, **prev; |
| 1478 | u_int curfrags; |
| 1479 | |
| 1480 | /* |
| 1481 | * Calculate the current number of frags. |
| 1482 | */ |
| 1483 | curfrags = 0; |
| 1484 | for (m = m0; m != NULL; m = m->m_next) |
| 1485 | curfrags += frags_per_mbuf(m); |
| 1486 | /* |
| 1487 | * First, try to collapse mbufs. Note that we always collapse |
| 1488 | * towards the front so we don't need to deal with moving the |
| 1489 | * pkthdr. This may be suboptimal if the first mbuf has much |
| 1490 | * less data than the following. |
| 1491 | */ |
| 1492 | m = m0; |
| 1493 | again: |
| 1494 | for (;;) { |
| 1495 | n = m->m_next; |
| 1496 | if (n == NULL) |
| 1497 | break; |
| 1498 | if (M_WRITABLE(m) && |
| 1499 | n->m_len < M_TRAILINGSPACE(m)) { |
| 1500 | m_copydata(n, 0, n->m_len, |
| 1501 | mtod(m, char *) + m->m_len); |
| 1502 | m->m_len += n->m_len; |
| 1503 | m->m_next = n->m_next; |
| 1504 | curfrags -= frags_per_mbuf(n); |
| 1505 | m_free(n); |
| 1506 | if (curfrags <= maxfrags) |
| 1507 | return m0; |
| 1508 | } else |
| 1509 | m = n; |
| 1510 | } |
| 1511 | KASSERT(maxfrags > 1, |
| 1512 | ("maxfrags %u, but normal collapse failed", maxfrags)); |
| 1513 | /* |
| 1514 | * Collapse consecutive mbufs to a cluster. |
| 1515 | */ |
| 1516 | prev = &m0->m_next; /* NB: not the first mbuf */ |
| 1517 | while ((n = *prev) != NULL) { |
| 1518 | if ((n2 = n->m_next) != NULL && |
| 1519 | n->m_len + n2->m_len < MCLBYTES) { |
| 1520 | m = m_getcl(how, MT_DATA, 0); |
| 1521 | if (m == NULL) |
| 1522 | goto bad; |
| 1523 | m_copydata(n, 0, n->m_len, mtod(m, char *)); |
| 1524 | m_copydata(n2, 0, n2->m_len, |
| 1525 | mtod(m, char *) + n->m_len); |
| 1526 | m->m_len = n->m_len + n2->m_len; |
| 1527 | m->m_next = n2->m_next; |
| 1528 | *prev = m; |
| 1529 | curfrags += 1; /* For the new cluster */ |
| 1530 | curfrags -= frags_per_mbuf(n); |
| 1531 | curfrags -= frags_per_mbuf(n2); |
no test coverage detected