|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.