123417Smckusick /* 223417Smckusick * Copyright (c) 1982 Regents of the University of California. 323417Smckusick * All rights reserved. The Berkeley software License Agreement 423417Smckusick * specifies the terms and conditions for redistribution. 523417Smckusick * 6*24764Skarels * @(#)uipc_mbuf.c 6.8 (Berkeley) 09/16/85 723417Smckusick */ 84585Swnj 99765Ssam #include "../machine/pte.h" 109765Ssam 1117102Sbloom #include "param.h" 1217102Sbloom #include "dir.h" 1317102Sbloom #include "user.h" 1417102Sbloom #include "proc.h" 1517102Sbloom #include "cmap.h" 1617102Sbloom #include "map.h" 1717102Sbloom #include "mbuf.h" 1817102Sbloom #include "vm.h" 1917102Sbloom #include "kernel.h" 204585Swnj 215228Swnj mbinit() 225228Swnj { 2321107Skarels int s; 245228Swnj 2521107Skarels s = splimp(); 2621107Skarels if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0) 275228Swnj goto bad; 2821107Skarels if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0) 295228Swnj goto bad; 3021107Skarels splx(s); 315228Swnj return; 325228Swnj bad: 335228Swnj panic("mbinit"); 345228Swnj } 355228Swnj 3621107Skarels /* 3721107Skarels * Must be called at splimp. 3821107Skarels */ 395228Swnj caddr_t 4021107Skarels m_clalloc(ncl, how, canwait) 415228Swnj register int ncl; 425228Swnj int how; 435228Swnj { 445228Swnj int npg, mbx; 455228Swnj register struct mbuf *m; 465228Swnj register int i; 475228Swnj 485228Swnj npg = ncl * CLSIZE; 498792Sroot mbx = rmalloc(mbmap, (long)npg); 5021107Skarels if (mbx == 0) { 5121107Skarels if (canwait == M_WAIT) 5221107Skarels panic("out of mbuf map"); 535228Swnj return (0); 5421107Skarels } 555228Swnj m = cltom(mbx / CLSIZE); 569765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 579765Ssam rmfree(mbmap, (long)npg, (long)mbx); 585228Swnj return (0); 599765Ssam } 605228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 615228Swnj switch (how) { 625228Swnj 635228Swnj case MPG_CLUSTERS: 645228Swnj for (i = 0; i < ncl; i++) { 655228Swnj m->m_off = 0; 665228Swnj m->m_next = mclfree; 675228Swnj mclfree = m; 685228Swnj m += CLBYTES / sizeof (*m); 696839Ssam mbstat.m_clfree++; 705228Swnj } 715228Swnj mbstat.m_clusters += ncl; 725228Swnj break; 735228Swnj 745228Swnj case MPG_MBUFS: 755228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 765228Swnj m->m_off = 0; 779634Ssam m->m_type = MT_DATA; 789634Ssam mbstat.m_mtypes[MT_DATA]++; 796839Ssam mbstat.m_mbufs++; 805228Swnj (void) m_free(m); 815228Swnj m++; 825228Swnj } 835232Swnj break; 845228Swnj } 855228Swnj return ((caddr_t)m); 865228Swnj } 875228Swnj 885228Swnj m_pgfree(addr, n) 895228Swnj caddr_t addr; 905228Swnj int n; 915228Swnj { 925228Swnj 936141Ssam #ifdef lint 946141Ssam addr = addr; n = n; 956141Ssam #endif 965228Swnj } 975228Swnj 9821107Skarels /* 9921107Skarels * Must be called at splimp. 10021107Skarels */ 10121107Skarels m_expand(canwait) 10221107Skarels int canwait; 1035228Swnj { 1045228Swnj 10521107Skarels if (m_clalloc(1, MPG_MBUFS, canwait) == 0) 1065228Swnj goto steal; 1075228Swnj return (1); 1085228Swnj steal: 1095228Swnj /* should ask protocols to free code */ 1105228Swnj return (0); 1115228Swnj } 1125228Swnj 1135228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1145228Swnj 1155228Swnj /* 1165228Swnj * Space allocation routines. 1175228Swnj * These are also available as macros 1185228Swnj * for critical paths. 1195228Swnj */ 1204585Swnj struct mbuf * 1219634Ssam m_get(canwait, type) 1229634Ssam int canwait, type; 1234585Swnj { 1244585Swnj register struct mbuf *m; 1254585Swnj 1269634Ssam MGET(m, canwait, type); 1274585Swnj return (m); 1284585Swnj } 1294585Swnj 1304585Swnj struct mbuf * 1319634Ssam m_getclr(canwait, type) 1329634Ssam int canwait, type; 1334890Swnj { 1344890Swnj register struct mbuf *m; 1354890Swnj 13621107Skarels MGET(m, canwait, type); 1374890Swnj if (m == 0) 1384890Swnj return (0); 1394890Swnj bzero(mtod(m, caddr_t), MLEN); 1404890Swnj return (m); 1414890Swnj } 1424890Swnj 1434890Swnj struct mbuf * 1444585Swnj m_free(m) 1454585Swnj struct mbuf *m; 1464585Swnj { 1474585Swnj register struct mbuf *n; 1484585Swnj 1494585Swnj MFREE(m, n); 1504585Swnj return (n); 1514585Swnj } 1524585Swnj 15321107Skarels /* 15421107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 15521107Skarels * Must be called at splimp. 15621107Skarels */ 1574916Swnj /*ARGSUSED*/ 1584585Swnj struct mbuf * 1599634Ssam m_more(canwait, type) 1609634Ssam int canwait, type; 1614585Swnj { 1624585Swnj register struct mbuf *m; 1634585Swnj 16421107Skarels while (m_expand(canwait) == 0) { 16521107Skarels if (canwait == M_WAIT) { 16621107Skarels m_want++; 16724546Skarels sleep((caddr_t)&mfree, PZERO - 1); 16821107Skarels } else { 16921107Skarels mbstat.m_drops++; 17021107Skarels return (NULL); 17121107Skarels } 1724585Swnj } 1739634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 1749634Ssam MGET(m, canwait, type); 1755282Sroot #undef m_more 1764585Swnj return (m); 1774585Swnj } 1784585Swnj 1794669Swnj m_freem(m) 1804585Swnj register struct mbuf *m; 1814585Swnj { 1824585Swnj register struct mbuf *n; 1834927Swnj register int s; 1844585Swnj 1854585Swnj if (m == NULL) 1864916Swnj return; 1874662Swnj s = splimp(); 1884585Swnj do { 1894585Swnj MFREE(m, n); 1904585Swnj } while (m = n); 1914585Swnj splx(s); 1924585Swnj } 1934585Swnj 1945228Swnj /* 1955228Swnj * Mbuffer utility routines. 1965228Swnj */ 19721107Skarels 19821107Skarels /* 19921107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 20021107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 20121107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 20221107Skarels */ 2034927Swnj struct mbuf * 2044927Swnj m_copy(m, off, len) 2054927Swnj register struct mbuf *m; 2064927Swnj int off; 2074927Swnj register int len; 2084927Swnj { 2094927Swnj register struct mbuf *n, **np; 2104927Swnj struct mbuf *top, *p; 2114927Swnj 2124927Swnj if (len == 0) 2134927Swnj return (0); 2144927Swnj if (off < 0 || len < 0) 2154927Swnj panic("m_copy"); 2164927Swnj while (off > 0) { 2174927Swnj if (m == 0) 2184927Swnj panic("m_copy"); 2194927Swnj if (off < m->m_len) 2204927Swnj break; 2214927Swnj off -= m->m_len; 2224927Swnj m = m->m_next; 2234927Swnj } 2244927Swnj np = ⊤ 2254927Swnj top = 0; 2264927Swnj while (len > 0) { 2275609Swnj if (m == 0) { 2285609Swnj if (len != M_COPYALL) 2295609Swnj panic("m_copy"); 2305609Swnj break; 2315609Swnj } 23221107Skarels MGET(n, M_DONTWAIT, m->m_type); 2334927Swnj *np = n; 2344927Swnj if (n == 0) 2354927Swnj goto nospace; 2364927Swnj n->m_len = MIN(len, m->m_len - off); 2374927Swnj if (m->m_off > MMAXOFF) { 2384927Swnj p = mtod(m, struct mbuf *); 2394927Swnj n->m_off = ((int)p - (int)n) + off; 2405090Swnj mclrefcnt[mtocl(p)]++; 2418318Sroot } else 2424927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2434927Swnj (unsigned)n->m_len); 2445609Swnj if (len != M_COPYALL) 2455609Swnj len -= n->m_len; 2464927Swnj off = 0; 2474927Swnj m = m->m_next; 2484927Swnj np = &n->m_next; 2494927Swnj } 2504927Swnj return (top); 2514927Swnj nospace: 2524927Swnj m_freem(top); 2534927Swnj return (0); 2544927Swnj } 2554927Swnj 2564669Swnj m_cat(m, n) 2574669Swnj register struct mbuf *m, *n; 2584669Swnj { 2594669Swnj while (m->m_next) 2604669Swnj m = m->m_next; 2616091Sroot while (n) { 2626091Sroot if (m->m_off >= MMAXOFF || 2636091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2646091Sroot /* just join the two chains */ 2654669Swnj m->m_next = n; 2666091Sroot return; 2674669Swnj } 2686091Sroot /* splat the data from one into the other */ 2696091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 2706091Sroot (u_int)n->m_len); 2716091Sroot m->m_len += n->m_len; 2726091Sroot n = m_free(n); 2736091Sroot } 2744669Swnj } 2754669Swnj 2764585Swnj m_adj(mp, len) 2774585Swnj struct mbuf *mp; 2784916Swnj register int len; 2794585Swnj { 280*24764Skarels register struct mbuf *m; 281*24764Skarels register count; 2824585Swnj 2834585Swnj if ((m = mp) == NULL) 2844585Swnj return; 2854822Swnj if (len >= 0) { 2864585Swnj while (m != NULL && len > 0) { 2874822Swnj if (m->m_len <= len) { 2884585Swnj len -= m->m_len; 2894585Swnj m->m_len = 0; 2904585Swnj m = m->m_next; 2914822Swnj } else { 2924585Swnj m->m_len -= len; 2934585Swnj m->m_off += len; 2944585Swnj break; 2954585Swnj } 2964585Swnj } 2974822Swnj } else { 298*24764Skarels /* 299*24764Skarels * Trim from tail. Scan the mbuf chain, 300*24764Skarels * calculating its length and finding the last mbuf. 301*24764Skarels * If the adjustment only affects this mbuf, then just 302*24764Skarels * adjust and return. Otherwise, rescan and truncate 303*24764Skarels * after the remaining size. 304*24764Skarels */ 3054585Swnj len = -len; 306*24764Skarels count = 0; 307*24764Skarels for (;;) { 308*24764Skarels count += m->m_len; 309*24764Skarels if (m->m_next == (struct mbuf *)0) 3104585Swnj break; 311*24764Skarels m = m->m_next; 312*24764Skarels } 313*24764Skarels if (m->m_len >= len) { 314*24764Skarels m->m_len -= len; 315*24764Skarels return; 316*24764Skarels } 317*24764Skarels count -= len; 318*24764Skarels /* 319*24764Skarels * Correct length for chain is "count". 320*24764Skarels * Find the mbuf with last data, adjust its length, 321*24764Skarels * and toss data from remaining mbufs on chain. 322*24764Skarels */ 323*24764Skarels for (m = mp; m; m = m->m_next) { 324*24764Skarels if (m->m_len >= count) { 325*24764Skarels m->m_len = count; 326*24764Skarels break; 3274585Swnj } 328*24764Skarels count -= m->m_len; 3294585Swnj } 330*24764Skarels while (m = m->m_next) 331*24764Skarels m->m_len = 0; 3324585Swnj } 3334585Swnj } 3345228Swnj 33523816Skarels /* 33623816Skarels * Rearange an mbuf chain so that len bytes are contiguous 33723816Skarels * and in the data area of an mbuf (so that mtod and dtom 338*24764Skarels * will work for a structure of size len). Returns the resulting 339*24764Skarels * mbuf chain on success, frees it and returns null on failure. 340*24764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 341*24764Skarels * contiguous region in an attempt to avoid being called next time. 34223816Skarels */ 3435310Sroot struct mbuf * 344*24764Skarels m_pullup(n, len) 345*24764Skarels register struct mbuf *n; 3465228Swnj int len; 3475228Swnj { 348*24764Skarels register struct mbuf *m; 349*24764Skarels register int count; 350*24764Skarels int space; 3515228Swnj 352*24764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 353*24764Skarels m = n; 354*24764Skarels n = n->m_next; 355*24764Skarels len -= m->m_len; 356*24764Skarels } else { 357*24764Skarels if (len > MLEN) 358*24764Skarels goto bad; 359*24764Skarels MGET(m, M_DONTWAIT, n->m_type); 360*24764Skarels if (m == 0) 361*24764Skarels goto bad; 362*24764Skarels m->m_len = 0; 363*24764Skarels } 364*24764Skarels space = MMAXOFF - m->m_off; 3655310Sroot do { 366*24764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 3676164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3686164Ssam (unsigned)count); 3696164Ssam len -= count; 3706164Ssam m->m_len += count; 3716164Ssam n->m_len -= count; 3725310Sroot if (n->m_len) 37323816Skarels n->m_off += count; 37423816Skarels else 37523816Skarels n = m_free(n); 376*24764Skarels } while (len > 0 && n); 377*24764Skarels if (len > 0) { 3785310Sroot (void) m_free(m); 3795310Sroot goto bad; 3805310Sroot } 3815310Sroot m->m_next = n; 3825310Sroot return (m); 3835310Sroot bad: 3845732Sroot m_freem(n); 3855228Swnj return (0); 3865228Swnj } 387