1*21107Skarels /* uipc_mbuf.c 6.4 85/05/27 */ 24585Swnj 39765Ssam #include "../machine/pte.h" 49765Ssam 517102Sbloom #include "param.h" 617102Sbloom #include "dir.h" 717102Sbloom #include "user.h" 817102Sbloom #include "proc.h" 917102Sbloom #include "cmap.h" 1017102Sbloom #include "map.h" 1117102Sbloom #include "mbuf.h" 1217102Sbloom #include "vm.h" 1317102Sbloom #include "kernel.h" 144585Swnj 155228Swnj mbinit() 165228Swnj { 17*21107Skarels int s; 185228Swnj 19*21107Skarels s = splimp(); 20*21107Skarels if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0) 215228Swnj goto bad; 22*21107Skarels if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0) 235228Swnj goto bad; 24*21107Skarels splx(s); 255228Swnj return; 265228Swnj bad: 275228Swnj panic("mbinit"); 285228Swnj } 295228Swnj 30*21107Skarels /* 31*21107Skarels * Must be called at splimp. 32*21107Skarels */ 335228Swnj caddr_t 34*21107Skarels m_clalloc(ncl, how, canwait) 355228Swnj register int ncl; 365228Swnj int how; 375228Swnj { 385228Swnj int npg, mbx; 395228Swnj register struct mbuf *m; 405228Swnj register int i; 415228Swnj 425228Swnj npg = ncl * CLSIZE; 438792Sroot mbx = rmalloc(mbmap, (long)npg); 44*21107Skarels if (mbx == 0) { 45*21107Skarels if (canwait == M_WAIT) 46*21107Skarels panic("out of mbuf map"); 475228Swnj return (0); 48*21107Skarels } 495228Swnj m = cltom(mbx / CLSIZE); 509765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 519765Ssam rmfree(mbmap, (long)npg, (long)mbx); 525228Swnj return (0); 539765Ssam } 545228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 555228Swnj switch (how) { 565228Swnj 575228Swnj case MPG_CLUSTERS: 585228Swnj for (i = 0; i < ncl; i++) { 595228Swnj m->m_off = 0; 605228Swnj m->m_next = mclfree; 615228Swnj mclfree = m; 625228Swnj m += CLBYTES / sizeof (*m); 636839Ssam mbstat.m_clfree++; 645228Swnj } 655228Swnj mbstat.m_clusters += ncl; 665228Swnj break; 675228Swnj 685228Swnj case MPG_MBUFS: 695228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 705228Swnj m->m_off = 0; 719634Ssam m->m_type = MT_DATA; 729634Ssam mbstat.m_mtypes[MT_DATA]++; 736839Ssam mbstat.m_mbufs++; 745228Swnj (void) m_free(m); 755228Swnj m++; 765228Swnj } 775232Swnj break; 785228Swnj } 795228Swnj return ((caddr_t)m); 805228Swnj } 815228Swnj 825228Swnj m_pgfree(addr, n) 835228Swnj caddr_t addr; 845228Swnj int n; 855228Swnj { 865228Swnj 876141Ssam #ifdef lint 886141Ssam addr = addr; n = n; 896141Ssam #endif 905228Swnj } 915228Swnj 92*21107Skarels /* 93*21107Skarels * Must be called at splimp. 94*21107Skarels */ 95*21107Skarels m_expand(canwait) 96*21107Skarels int canwait; 975228Swnj { 985228Swnj 99*21107Skarels if (m_clalloc(1, MPG_MBUFS, canwait) == 0) 1005228Swnj goto steal; 1015228Swnj return (1); 1025228Swnj steal: 1035228Swnj /* should ask protocols to free code */ 1045228Swnj return (0); 1055228Swnj } 1065228Swnj 1075228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1085228Swnj 1095228Swnj /* 1105228Swnj * Space allocation routines. 1115228Swnj * These are also available as macros 1125228Swnj * for critical paths. 1135228Swnj */ 1144585Swnj struct mbuf * 1159634Ssam m_get(canwait, type) 1169634Ssam int canwait, type; 1174585Swnj { 1184585Swnj register struct mbuf *m; 1194585Swnj 1209634Ssam MGET(m, canwait, type); 1214585Swnj return (m); 1224585Swnj } 1234585Swnj 1244585Swnj struct mbuf * 1259634Ssam m_getclr(canwait, type) 1269634Ssam int canwait, type; 1274890Swnj { 1284890Swnj register struct mbuf *m; 1294890Swnj 130*21107Skarels MGET(m, canwait, type); 1314890Swnj if (m == 0) 1324890Swnj return (0); 1334890Swnj bzero(mtod(m, caddr_t), MLEN); 1344890Swnj return (m); 1354890Swnj } 1364890Swnj 1374890Swnj struct mbuf * 1384585Swnj m_free(m) 1394585Swnj struct mbuf *m; 1404585Swnj { 1414585Swnj register struct mbuf *n; 1424585Swnj 1434585Swnj MFREE(m, n); 1444585Swnj return (n); 1454585Swnj } 1464585Swnj 147*21107Skarels /* 148*21107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 149*21107Skarels * Must be called at splimp. 150*21107Skarels */ 1514916Swnj /*ARGSUSED*/ 1524585Swnj struct mbuf * 1539634Ssam m_more(canwait, type) 1549634Ssam int canwait, type; 1554585Swnj { 1564585Swnj register struct mbuf *m; 1574585Swnj 158*21107Skarels while (m_expand(canwait) == 0) { 159*21107Skarels if (canwait == M_WAIT) { 160*21107Skarels m_want++; 161*21107Skarels sleep((caddr_t)mfree, PZERO - 1); 162*21107Skarels } else { 163*21107Skarels mbstat.m_drops++; 164*21107Skarels return (NULL); 165*21107Skarels } 1664585Swnj } 1679634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 1689634Ssam MGET(m, canwait, type); 1695282Sroot #undef m_more 1704585Swnj return (m); 1714585Swnj } 1724585Swnj 1734669Swnj m_freem(m) 1744585Swnj register struct mbuf *m; 1754585Swnj { 1764585Swnj register struct mbuf *n; 1774927Swnj register int s; 1784585Swnj 1794585Swnj if (m == NULL) 1804916Swnj return; 1814662Swnj s = splimp(); 1824585Swnj do { 1834585Swnj MFREE(m, n); 1844585Swnj } while (m = n); 1854585Swnj splx(s); 1864585Swnj } 1874585Swnj 1885228Swnj /* 1895228Swnj * Mbuffer utility routines. 1905228Swnj */ 191*21107Skarels 192*21107Skarels /* 193*21107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 194*21107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 195*21107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 196*21107Skarels */ 1974927Swnj struct mbuf * 1984927Swnj m_copy(m, off, len) 1994927Swnj register struct mbuf *m; 2004927Swnj int off; 2014927Swnj register int len; 2024927Swnj { 2034927Swnj register struct mbuf *n, **np; 2044927Swnj struct mbuf *top, *p; 2054927Swnj 2064927Swnj if (len == 0) 2074927Swnj return (0); 2084927Swnj if (off < 0 || len < 0) 2094927Swnj panic("m_copy"); 2104927Swnj while (off > 0) { 2114927Swnj if (m == 0) 2124927Swnj panic("m_copy"); 2134927Swnj if (off < m->m_len) 2144927Swnj break; 2154927Swnj off -= m->m_len; 2164927Swnj m = m->m_next; 2174927Swnj } 2184927Swnj np = ⊤ 2194927Swnj top = 0; 2204927Swnj while (len > 0) { 2215609Swnj if (m == 0) { 2225609Swnj if (len != M_COPYALL) 2235609Swnj panic("m_copy"); 2245609Swnj break; 2255609Swnj } 226*21107Skarels MGET(n, M_DONTWAIT, m->m_type); 2274927Swnj *np = n; 2284927Swnj if (n == 0) 2294927Swnj goto nospace; 2304927Swnj n->m_len = MIN(len, m->m_len - off); 2314927Swnj if (m->m_off > MMAXOFF) { 2324927Swnj p = mtod(m, struct mbuf *); 2334927Swnj n->m_off = ((int)p - (int)n) + off; 2345090Swnj mclrefcnt[mtocl(p)]++; 2358318Sroot } else 2364927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2374927Swnj (unsigned)n->m_len); 2385609Swnj if (len != M_COPYALL) 2395609Swnj len -= n->m_len; 2404927Swnj off = 0; 2414927Swnj m = m->m_next; 2424927Swnj np = &n->m_next; 2434927Swnj } 2444927Swnj return (top); 2454927Swnj nospace: 2464927Swnj m_freem(top); 2474927Swnj return (0); 2484927Swnj } 2494927Swnj 2504669Swnj m_cat(m, n) 2514669Swnj register struct mbuf *m, *n; 2524669Swnj { 2534669Swnj while (m->m_next) 2544669Swnj m = m->m_next; 2556091Sroot while (n) { 2566091Sroot if (m->m_off >= MMAXOFF || 2576091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2586091Sroot /* just join the two chains */ 2594669Swnj m->m_next = n; 2606091Sroot return; 2614669Swnj } 2626091Sroot /* splat the data from one into the other */ 2636091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 2646091Sroot (u_int)n->m_len); 2656091Sroot m->m_len += n->m_len; 2666091Sroot n = m_free(n); 2676091Sroot } 2684669Swnj } 2694669Swnj 2704585Swnj m_adj(mp, len) 2714585Swnj struct mbuf *mp; 2724916Swnj register int len; 2734585Swnj { 2744585Swnj register struct mbuf *m, *n; 2754585Swnj 2764585Swnj if ((m = mp) == NULL) 2774585Swnj return; 2784822Swnj if (len >= 0) { 2794585Swnj while (m != NULL && len > 0) { 2804822Swnj if (m->m_len <= len) { 2814585Swnj len -= m->m_len; 2824585Swnj m->m_len = 0; 2834585Swnj m = m->m_next; 2844822Swnj } else { 2854585Swnj m->m_len -= len; 2864585Swnj m->m_off += len; 2874585Swnj break; 2884585Swnj } 2894585Swnj } 2904822Swnj } else { 2914822Swnj /* a 2 pass algorithm might be better */ 2924585Swnj len = -len; 2934585Swnj while (len > 0 && m->m_len != 0) { 2944585Swnj while (m != NULL && m->m_len != 0) { 2954585Swnj n = m; 2964585Swnj m = m->m_next; 2974585Swnj } 2984822Swnj if (n->m_len <= len) { 2994585Swnj len -= n->m_len; 3004585Swnj n->m_len = 0; 3014585Swnj m = mp; 3024822Swnj } else { 3034585Swnj n->m_len -= len; 3044585Swnj break; 3054585Swnj } 3064585Swnj } 3074585Swnj } 3084585Swnj } 3095228Swnj 3105310Sroot struct mbuf * 3115310Sroot m_pullup(m0, len) 3125310Sroot struct mbuf *m0; 3135228Swnj int len; 3145228Swnj { 3155310Sroot register struct mbuf *m, *n; 3166164Ssam int count; 3175228Swnj 3185732Sroot n = m0; 3195310Sroot if (len > MLEN) 3205310Sroot goto bad; 3219634Ssam MGET(m, M_DONTWAIT, n->m_type); 3225310Sroot if (m == 0) 3235310Sroot goto bad; 3245310Sroot m->m_len = 0; 3255310Sroot do { 3266164Ssam count = MIN(MLEN - m->m_len, len); 3276164Ssam if (count > n->m_len) 3286164Ssam count = n->m_len; 3296164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3306164Ssam (unsigned)count); 3316164Ssam len -= count; 3326164Ssam m->m_len += count; 3336164Ssam n->m_off += count; 3346164Ssam n->m_len -= count; 3355310Sroot if (n->m_len) 3365310Sroot break; 3375310Sroot n = m_free(n); 3385310Sroot } while (n); 3395310Sroot if (len) { 3405310Sroot (void) m_free(m); 3415310Sroot goto bad; 3425310Sroot } 3435310Sroot m->m_next = n; 3445310Sroot return (m); 3455310Sroot bad: 3465732Sroot m_freem(n); 3475228Swnj return (0); 3485228Swnj } 349