home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / kern / uipc_mbuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  10.5 KB  |  517 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)uipc_mbuf.c    7.19 (Berkeley) 4/20/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "proc.h"
  38. #include "malloc.h"
  39. #include "map.h"
  40. #define MBTYPES
  41. #include "mbuf.h"
  42. #include "kernel.h"
  43. #include "syslog.h"
  44. #include "domain.h"
  45. #include "protosw.h"
  46. #include "vm/vm.h"
  47.  
  48. extern    vm_map_t mb_map;
  49. struct    mbuf *mbutl;
  50. char    *mclrefcnt;
  51.  
  52. mbinit()
  53. {
  54.     int s;
  55.  
  56. #if CLBYTES < 4096
  57. #define NCL_INIT    (4096/CLBYTES)
  58. #else
  59. #define NCL_INIT    1
  60. #endif
  61.     s = splimp();
  62.     if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
  63.         goto bad;
  64.     splx(s);
  65.     return;
  66. bad:
  67.     panic("mbinit");
  68. }
  69.  
  70. /*
  71.  * Allocate some number of mbuf clusters
  72.  * and place on cluster free list.
  73.  * Must be called at splimp.
  74.  */
  75. /* ARGSUSED */
  76. m_clalloc(ncl, canwait)
  77.     register int ncl;
  78. {
  79.     int npg, mbx;
  80.     register caddr_t p;
  81.     register int i;
  82.     static int logged;
  83.  
  84.     npg = ncl * CLSIZE;
  85.     p = (caddr_t)kmem_malloc(mb_map, ctob(npg), canwait);
  86.     if (p == NULL) {
  87.         if (logged == 0) {
  88.             logged++;
  89.             log(LOG_ERR, "mb_map full\n");
  90.         }
  91.         return (0);
  92.     }
  93.     ncl = ncl * CLBYTES / MCLBYTES;
  94.     for (i = 0; i < ncl; i++) {
  95.         ((union mcluster *)p)->mcl_next = mclfree;
  96.         mclfree = (union mcluster *)p;
  97.         p += MCLBYTES;
  98.         mbstat.m_clfree++;
  99.     }
  100.     mbstat.m_clusters += ncl;
  101.     return (1);
  102. }
  103.  
  104. /*
  105.  * When MGET failes, ask protocols to free space when short of memory,
  106.  * then re-attempt to allocate an mbuf.
  107.  */
  108. struct mbuf *
  109. m_retry(i, t)
  110.     int i, t;
  111. {
  112.     register struct mbuf *m;
  113.  
  114.     m_reclaim();
  115. #define m_retry(i, t)    (struct mbuf *)0
  116.     MGET(m, i, t);
  117. #undef m_retry
  118.     return (m);
  119. }
  120.  
  121. /*
  122.  * As above; retry an MGETHDR.
  123.  */
  124. struct mbuf *
  125. m_retryhdr(i, t)
  126.     int i, t;
  127. {
  128.     register struct mbuf *m;
  129.  
  130.     m_reclaim();
  131. #define m_retryhdr(i, t) (struct mbuf *)0
  132.     MGETHDR(m, i, t);
  133. #undef m_retryhdr
  134.     return (m);
  135. }
  136.  
  137. m_reclaim()
  138. {
  139.     register struct domain *dp;
  140.     register struct protosw *pr;
  141.     int s = splimp();
  142.  
  143.     for (dp = domains; dp; dp = dp->dom_next)
  144.         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
  145.             if (pr->pr_drain)
  146.                 (*pr->pr_drain)();
  147.     splx(s);
  148.     mbstat.m_drain++;
  149. }
  150.  
  151. /*
  152.  * Space allocation routines.
  153.  * These are also available as macros
  154.  * for critical paths.
  155.  */
  156. struct mbuf *
  157. m_get(canwait, type)
  158.     int canwait, type;
  159. {
  160.     register struct mbuf *m;
  161.  
  162.     MGET(m, canwait, type);
  163.     return (m);
  164. }
  165.  
  166. struct mbuf *
  167. m_gethdr(canwait, type)
  168.     int canwait, type;
  169. {
  170.     register struct mbuf *m;
  171.  
  172.     MGETHDR(m, canwait, type);
  173.     return (m);
  174. }
  175.  
  176. struct mbuf *
  177. m_getclr(canwait, type)
  178.     int canwait, type;
  179. {
  180.     register struct mbuf *m;
  181.  
  182.     MGET(m, canwait, type);
  183.     if (m == 0)
  184.         return (0);
  185.     bzero(mtod(m, caddr_t), MLEN);
  186.     return (m);
  187. }
  188.  
  189. struct mbuf *
  190. m_free(m)
  191.     struct mbuf *m;
  192. {
  193.     register struct mbuf *n;
  194.  
  195.     MFREE(m, n);
  196.     return (n);
  197. }
  198.  
  199. m_freem(m)
  200.     register struct mbuf *m;
  201. {
  202.     register struct mbuf *n;
  203.  
  204.     if (m == NULL)
  205.         return;
  206.     do {
  207.         MFREE(m, n);
  208.     } while (m = n);
  209. }
  210.  
  211. /*
  212.  * Mbuffer utility routines.
  213.  */
  214.  
  215. /*
  216.  * Lesser-used path for M_PREPEND:
  217.  * allocate new mbuf to prepend to chain,
  218.  * copy junk along.
  219.  */
  220. struct mbuf *
  221. m_prepend(m, len, how)
  222.     register struct mbuf *m;
  223.     int len, how;
  224. {
  225.     struct mbuf *mn;
  226.  
  227.     MGET(mn, how, m->m_type);
  228.     if (mn == (struct mbuf *)NULL) {
  229.         m_freem(m);
  230.         return ((struct mbuf *)NULL);
  231.     }
  232.     if (m->m_flags & M_PKTHDR) {
  233.         M_COPY_PKTHDR(mn, m);
  234.         m->m_flags &= ~M_PKTHDR;
  235.     }
  236.     mn->m_next = m;
  237.     m = mn;
  238.     if (len < MHLEN)
  239.         MH_ALIGN(m, len);
  240.     m->m_len = len;
  241.     return (m);
  242. }
  243.  
  244. /*
  245.  * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
  246.  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
  247.  * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
  248.  */
  249. int MCFail;
  250.  
  251. struct mbuf *
  252. m_copym(m, off0, len, wait)
  253.     register struct mbuf *m;
  254.     int off0, wait;
  255.     register int len;
  256. {
  257.     register struct mbuf *n, **np;
  258.     register int off = off0;
  259.     struct mbuf *top;
  260.     int copyhdr = 0;
  261.  
  262.     if (off < 0 || len < 0)
  263.         panic("m_copym");
  264.     if (off == 0 && m->m_flags & M_PKTHDR)
  265.         copyhdr = 1;
  266.     while (off > 0) {
  267.         if (m == 0)
  268.             panic("m_copym");
  269.         if (off < m->m_len)
  270.             break;
  271.         off -= m->m_len;
  272.         m = m->m_next;
  273.     }
  274.     np = ⊤
  275.     top = 0;
  276.     while (len > 0) {
  277.         if (m == 0) {
  278.             if (len != M_COPYALL)
  279.                 panic("m_copym");
  280.             break;
  281.         }
  282.         MGET(n, wait, m->m_type);
  283.         *np = n;
  284.         if (n == 0)
  285.             goto nospace;
  286.         if (copyhdr) {
  287.             M_COPY_PKTHDR(n, m);
  288.             if (len == M_COPYALL)
  289.                 n->m_pkthdr.len -= off0;
  290.             else
  291.                 n->m_pkthdr.len = len;
  292.             copyhdr = 0;
  293.         }
  294.         n->m_len = MIN(len, m->m_len - off);
  295.         if (m->m_flags & M_EXT) {
  296.             n->m_data = m->m_data + off;
  297.             mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
  298.             n->m_ext = m->m_ext;
  299.             n->m_flags |= M_EXT;
  300.         } else
  301.             bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
  302.                 (unsigned)n->m_len);
  303.         if (len != M_COPYALL)
  304.             len -= n->m_len;
  305.         off = 0;
  306.         m = m->m_next;
  307.         np = &n->m_next;
  308.     }
  309.     if (top == 0)
  310.         MCFail++;
  311.     return (top);
  312. nospace:
  313.     m_freem(top);
  314.     MCFail++;
  315.     return (0);
  316. }
  317.  
  318. /*
  319.  * Copy data from an mbuf chain starting "off" bytes from the beginning,
  320.  * continuing for "len" bytes, into the indicated buffer.
  321.  */
  322. m_copydata(m, off, len, cp)
  323.     register struct mbuf *m;
  324.     register int off;
  325.     register int len;
  326.     caddr_t cp;
  327. {
  328.     register unsigned count;
  329.  
  330.     if (off < 0 || len < 0)
  331.         panic("m_copydata");
  332.     while (off > 0) {
  333.         if (m == 0)
  334.             panic("m_copydata");
  335.         if (off < m->m_len)
  336.             break;
  337.         off -= m->m_len;
  338.         m = m->m_next;
  339.     }
  340.     while (len > 0) {
  341.         if (m == 0)
  342.             panic("m_copydata");
  343.         count = MIN(m->m_len - off, len);
  344.         bcopy(mtod(m, caddr_t) + off, cp, count);
  345.         len -= count;
  346.         cp += count;
  347.         off = 0;
  348.         m = m->m_next;
  349.     }
  350. }
  351.  
  352. /*
  353.  * Concatenate mbuf chain n to m.
  354.  * Both chains must be of the same type (e.g. MT_DATA).
  355.  * Any m_pkthdr is not updated.
  356.  */
  357. m_cat(m, n)
  358.     register struct mbuf *m, *n;
  359. {
  360.     while (m->m_next)
  361.         m = m->m_next;
  362.     while (n) {
  363.         if (m->m_flags & M_EXT ||
  364.             m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
  365.             /* just join the two chains */
  366.             m->m_next = n;
  367.             return;
  368.         }
  369.         /* splat the data from one into the other */
  370.         bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
  371.             (u_int)n->m_len);
  372.         m->m_len += n->m_len;
  373.         n = m_free(n);
  374.     }
  375. }
  376.  
  377. m_adj(mp, req_len)
  378.     struct mbuf *mp;
  379. {
  380.     register int len = req_len;
  381.     register struct mbuf *m;
  382.     register count;
  383.  
  384.     if ((m = mp) == NULL)
  385.         return;
  386.     if (len >= 0) {
  387.         /*
  388.          * Trim from head.
  389.          */
  390.         while (m != NULL && len > 0) {
  391.             if (m->m_len <= len) {
  392.                 len -= m->m_len;
  393.                 m->m_len = 0;
  394.                 m = m->m_next;
  395.             } else {
  396.                 m->m_len -= len;
  397.                 m->m_data += len;
  398.                 len = 0;
  399.             }
  400.         }
  401.         m = mp;
  402.         if (mp->m_flags & M_PKTHDR)
  403.             m->m_pkthdr.len -= (req_len - len);
  404.     } else {
  405.         /*
  406.          * Trim from tail.  Scan the mbuf chain,
  407.          * calculating its length and finding the last mbuf.
  408.          * If the adjustment only affects this mbuf, then just
  409.          * adjust and return.  Otherwise, rescan and truncate
  410.          * after the remaining size.
  411.          */
  412.         len = -len;
  413.         count = 0;
  414.         for (;;) {
  415.             count += m->m_len;
  416.             if (m->m_next == (struct mbuf *)0)
  417.                 break;
  418.             m = m->m_next;
  419.         }
  420.         if (m->m_len >= len) {
  421.             m->m_len -= len;
  422.             if ((mp = m)->m_flags & M_PKTHDR)
  423.                 m->m_pkthdr.len -= len;
  424.             return;
  425.         }
  426.         count -= len;
  427.         if (count < 0)
  428.             count = 0;
  429.         /*
  430.          * Correct length for chain is "count".
  431.          * Find the mbuf with last data, adjust its length,
  432.          * and toss data from remaining mbufs on chain.
  433.          */
  434.         m = mp;
  435.         if (m->m_flags & M_PKTHDR)
  436.             m->m_pkthdr.len = count;
  437.         for (; m; m = m->m_next) {
  438.             if (m->m_len >= count) {
  439.                 m->m_len = count;
  440.                 break;
  441.             }
  442.             count -= m->m_len;
  443.         }
  444.         while (m = m->m_next)
  445.             m->m_len = 0;
  446.     }
  447. }
  448.  
  449. /*
  450.  * Rearange an mbuf chain so that len bytes are contiguous
  451.  * and in the data area of an mbuf (so that mtod and dtom
  452.  * will work for a structure of size len).  Returns the resulting
  453.  * mbuf chain on success, frees it and returns null on failure.
  454.  * If there is room, it will add up to max_protohdr-len extra bytes to the
  455.  * contiguous region in an attempt to avoid being called next time.
  456.  */
  457. int MPFail;
  458.  
  459. struct mbuf *
  460. m_pullup(n, len)
  461.     register struct mbuf *n;
  462.     int len;
  463. {
  464.     register struct mbuf *m;
  465.     register int count;
  466.     int space;
  467.  
  468.     /*
  469.      * If first mbuf has no cluster, and has room for len bytes
  470.      * without shifting current data, pullup into it,
  471.      * otherwise allocate a new mbuf to prepend to the chain.
  472.      */
  473.     if ((n->m_flags & M_EXT) == 0 &&
  474.         n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
  475.         if (n->m_len >= len)
  476.             return (n);
  477.         m = n;
  478.         n = n->m_next;
  479.         len -= m->m_len;
  480.     } else {
  481.         if (len > MHLEN)
  482.             goto bad;
  483.         MGET(m, M_DONTWAIT, n->m_type);
  484.         if (m == 0)
  485.             goto bad;
  486.         m->m_len = 0;
  487.         if (n->m_flags & M_PKTHDR) {
  488.             M_COPY_PKTHDR(m, n);
  489.             n->m_flags &= ~M_PKTHDR;
  490.         }
  491.     }
  492.     space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
  493.     do {
  494.         count = min(min(max(len, max_protohdr), space), n->m_len);
  495.         bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
  496.           (unsigned)count);
  497.         len -= count;
  498.         m->m_len += count;
  499.         n->m_len -= count;
  500.         space -= count;
  501.         if (n->m_len)
  502.             n->m_data += count;
  503.         else
  504.             n = m_free(n);
  505.     } while (len > 0 && n);
  506.     if (len > 0) {
  507.         (void) m_free(m);
  508.         goto bad;
  509.     }
  510.     m->m_next = n;
  511.     return (m);
  512. bad:
  513.     m_freem(n);
  514.     MPFail++;
  515.     return (0);
  516. }
  517.