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*24546Skarels * @(#)uipc_mbuf.c 6.7 (Berkeley) 09/05/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++; 167*24546Skarels 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 { 2804585Swnj register struct mbuf *m, *n; 2814585Swnj 2824585Swnj if ((m = mp) == NULL) 2834585Swnj return; 2844822Swnj if (len >= 0) { 2854585Swnj while (m != NULL && len > 0) { 2864822Swnj if (m->m_len <= len) { 2874585Swnj len -= m->m_len; 2884585Swnj m->m_len = 0; 2894585Swnj m = m->m_next; 2904822Swnj } else { 2914585Swnj m->m_len -= len; 2924585Swnj m->m_off += len; 2934585Swnj break; 2944585Swnj } 2954585Swnj } 2964822Swnj } else { 2974822Swnj /* a 2 pass algorithm might be better */ 2984585Swnj len = -len; 2994585Swnj while (len > 0 && m->m_len != 0) { 3004585Swnj while (m != NULL && m->m_len != 0) { 3014585Swnj n = m; 3024585Swnj m = m->m_next; 3034585Swnj } 3044822Swnj if (n->m_len <= len) { 3054585Swnj len -= n->m_len; 3064585Swnj n->m_len = 0; 3074585Swnj m = mp; 3084822Swnj } else { 3094585Swnj n->m_len -= len; 3104585Swnj break; 3114585Swnj } 3124585Swnj } 3134585Swnj } 3144585Swnj } 3155228Swnj 31623816Skarels /* 31723816Skarels * Rearange an mbuf chain so that len bytes are contiguous 31823816Skarels * and in the data area of an mbuf (so that mtod and dtom 31923816Skarels * will work for a structure of size len). 32023816Skarels * Returns the resulting mbuf chain on success, 32123816Skarels * frees it and returns null on failure. 32223816Skarels */ 3235310Sroot struct mbuf * 3245310Sroot m_pullup(m0, len) 3255310Sroot struct mbuf *m0; 3265228Swnj int len; 3275228Swnj { 3285310Sroot register struct mbuf *m, *n; 3296164Ssam int count; 3305228Swnj 3315732Sroot n = m0; 3325310Sroot if (len > MLEN) 3335310Sroot goto bad; 3349634Ssam MGET(m, M_DONTWAIT, n->m_type); 3355310Sroot if (m == 0) 3365310Sroot goto bad; 3375310Sroot m->m_len = 0; 3385310Sroot do { 33923816Skarels count = MIN(n->m_len, len); 3406164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3416164Ssam (unsigned)count); 3426164Ssam len -= count; 3436164Ssam m->m_len += count; 3446164Ssam n->m_len -= count; 3455310Sroot if (n->m_len) 34623816Skarels n->m_off += count; 34723816Skarels else 34823816Skarels n = m_free(n); 34923816Skarels } while (len && n); 3505310Sroot if (len) { 3515310Sroot (void) m_free(m); 3525310Sroot goto bad; 3535310Sroot } 3545310Sroot m->m_next = n; 3555310Sroot return (m); 3565310Sroot bad: 3575732Sroot m_freem(n); 3585228Swnj return (0); 3595228Swnj } 360