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