123417Smckusick /* 229124Smckusick * Copyright (c) 1982, 1986 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*32659Skarels * @(#)uipc_mbuf.c 7.4 (Berkeley) 11/23/87 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" 2030442Skarels #include "syslog.h" 2130442Skarels #include "domain.h" 2230442Skarels #include "protosw.h" 234585Swnj 245228Swnj mbinit() 255228Swnj { 2621107Skarels int s; 275228Swnj 28*32659Skarels #if CLBYTES < 4096 29*32659Skarels #define NCL_INIT (4096/CLBYTES) 30*32659Skarels #else 31*32659Skarels #define NCL_INIT 1 32*32659Skarels #endif 3321107Skarels s = splimp(); 34*32659Skarels if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0) 355228Swnj goto bad; 36*32659Skarels if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0) 375228Swnj goto bad; 3821107Skarels splx(s); 395228Swnj return; 405228Swnj bad: 415228Swnj panic("mbinit"); 425228Swnj } 435228Swnj 4421107Skarels /* 4521107Skarels * Must be called at splimp. 4621107Skarels */ 4730442Skarels /* ARGSUSED */ 485228Swnj caddr_t 4921107Skarels m_clalloc(ncl, how, canwait) 505228Swnj register int ncl; 515228Swnj int how; 525228Swnj { 535228Swnj int npg, mbx; 545228Swnj register struct mbuf *m; 555228Swnj register int i; 5630442Skarels static int logged; 575228Swnj 585228Swnj npg = ncl * CLSIZE; 598792Sroot mbx = rmalloc(mbmap, (long)npg); 6021107Skarels if (mbx == 0) { 6130442Skarels if (logged == 0) { 6230442Skarels logged++; 6330442Skarels log(LOG_ERR, "mbuf map full\n"); 6430442Skarels } 655228Swnj return (0); 6621107Skarels } 67*32659Skarels m = cltom(mbx * NBPG / MCLBYTES); 689765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 699765Ssam rmfree(mbmap, (long)npg, (long)mbx); 705228Swnj return (0); 719765Ssam } 725228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 735228Swnj switch (how) { 745228Swnj 755228Swnj case MPG_CLUSTERS: 76*32659Skarels ncl = ncl * CLBYTES / MCLBYTES; 775228Swnj for (i = 0; i < ncl; i++) { 785228Swnj m->m_off = 0; 795228Swnj m->m_next = mclfree; 805228Swnj mclfree = m; 81*32659Skarels m += MCLBYTES / sizeof (*m); 826839Ssam mbstat.m_clfree++; 835228Swnj } 845228Swnj mbstat.m_clusters += ncl; 855228Swnj break; 865228Swnj 875228Swnj case MPG_MBUFS: 885228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 895228Swnj m->m_off = 0; 909634Ssam m->m_type = MT_DATA; 919634Ssam mbstat.m_mtypes[MT_DATA]++; 926839Ssam mbstat.m_mbufs++; 935228Swnj (void) m_free(m); 945228Swnj m++; 955228Swnj } 965232Swnj break; 975228Swnj } 985228Swnj return ((caddr_t)m); 995228Swnj } 1005228Swnj 1015228Swnj m_pgfree(addr, n) 1025228Swnj caddr_t addr; 1035228Swnj int n; 1045228Swnj { 1055228Swnj 1066141Ssam #ifdef lint 1076141Ssam addr = addr; n = n; 1086141Ssam #endif 1095228Swnj } 1105228Swnj 11121107Skarels /* 11221107Skarels * Must be called at splimp. 11321107Skarels */ 11421107Skarels m_expand(canwait) 11521107Skarels int canwait; 1165228Swnj { 11730442Skarels register struct domain *dp; 11830442Skarels register struct protosw *pr; 11930442Skarels int tries; 1205228Swnj 12130442Skarels for (tries = 0;; ) { 12230442Skarels if (m_clalloc(1, MPG_MBUFS, canwait)) 12330442Skarels return (1); 12430442Skarels if (canwait == 0 || tries++) 12530442Skarels return (0); 12630442Skarels 12730442Skarels /* ask protocols to free space */ 12830442Skarels for (dp = domains; dp; dp = dp->dom_next) 12930442Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 13030442Skarels pr++) 13130442Skarels if (pr->pr_drain) 13230442Skarels (*pr->pr_drain)(); 13330442Skarels mbstat.m_drain++; 13430442Skarels } 1355228Swnj } 1365228Swnj 1375228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1385228Swnj 1395228Swnj /* 1405228Swnj * Space allocation routines. 1415228Swnj * These are also available as macros 1425228Swnj * for critical paths. 1435228Swnj */ 1444585Swnj struct mbuf * 1459634Ssam m_get(canwait, type) 1469634Ssam int canwait, type; 1474585Swnj { 1484585Swnj register struct mbuf *m; 1494585Swnj 1509634Ssam MGET(m, canwait, type); 1514585Swnj return (m); 1524585Swnj } 1534585Swnj 1544585Swnj struct mbuf * 1559634Ssam m_getclr(canwait, type) 1569634Ssam int canwait, type; 1574890Swnj { 1584890Swnj register struct mbuf *m; 1594890Swnj 16021107Skarels MGET(m, canwait, type); 1614890Swnj if (m == 0) 1624890Swnj return (0); 1634890Swnj bzero(mtod(m, caddr_t), MLEN); 1644890Swnj return (m); 1654890Swnj } 1664890Swnj 1674890Swnj struct mbuf * 1684585Swnj m_free(m) 1694585Swnj struct mbuf *m; 1704585Swnj { 1714585Swnj register struct mbuf *n; 1724585Swnj 1734585Swnj MFREE(m, n); 1744585Swnj return (n); 1754585Swnj } 1764585Swnj 17721107Skarels /* 17821107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 17921107Skarels * Must be called at splimp. 18021107Skarels */ 1814916Swnj /*ARGSUSED*/ 1824585Swnj struct mbuf * 1839634Ssam m_more(canwait, type) 1849634Ssam int canwait, type; 1854585Swnj { 1864585Swnj register struct mbuf *m; 1874585Swnj 18821107Skarels while (m_expand(canwait) == 0) { 18921107Skarels if (canwait == M_WAIT) { 19030442Skarels mbstat.m_wait++; 19121107Skarels m_want++; 19224546Skarels sleep((caddr_t)&mfree, PZERO - 1); 19321107Skarels } else { 19421107Skarels mbstat.m_drops++; 19521107Skarels return (NULL); 19621107Skarels } 1974585Swnj } 1989634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 1999634Ssam MGET(m, canwait, type); 2005282Sroot #undef m_more 2014585Swnj return (m); 2024585Swnj } 2034585Swnj 2044669Swnj m_freem(m) 2054585Swnj register struct mbuf *m; 2064585Swnj { 2074585Swnj register struct mbuf *n; 2084927Swnj register int s; 2094585Swnj 2104585Swnj if (m == NULL) 2114916Swnj return; 2124662Swnj s = splimp(); 2134585Swnj do { 2144585Swnj MFREE(m, n); 2154585Swnj } while (m = n); 2164585Swnj splx(s); 2174585Swnj } 2184585Swnj 2195228Swnj /* 2205228Swnj * Mbuffer utility routines. 2215228Swnj */ 22221107Skarels 22321107Skarels /* 22421107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 22521107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 22621107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 22721107Skarels */ 2284927Swnj struct mbuf * 2294927Swnj m_copy(m, off, len) 2304927Swnj register struct mbuf *m; 2314927Swnj int off; 2324927Swnj register int len; 2334927Swnj { 2344927Swnj register struct mbuf *n, **np; 2354927Swnj struct mbuf *top, *p; 2364927Swnj 2374927Swnj if (len == 0) 2384927Swnj return (0); 2394927Swnj if (off < 0 || len < 0) 2404927Swnj panic("m_copy"); 2414927Swnj while (off > 0) { 2424927Swnj if (m == 0) 2434927Swnj panic("m_copy"); 2444927Swnj if (off < m->m_len) 2454927Swnj break; 2464927Swnj off -= m->m_len; 2474927Swnj m = m->m_next; 2484927Swnj } 2494927Swnj np = ⊤ 2504927Swnj top = 0; 2514927Swnj while (len > 0) { 2525609Swnj if (m == 0) { 2535609Swnj if (len != M_COPYALL) 2545609Swnj panic("m_copy"); 2555609Swnj break; 2565609Swnj } 25721107Skarels MGET(n, M_DONTWAIT, m->m_type); 2584927Swnj *np = n; 2594927Swnj if (n == 0) 2604927Swnj goto nospace; 2614927Swnj n->m_len = MIN(len, m->m_len - off); 2624927Swnj if (m->m_off > MMAXOFF) { 2634927Swnj p = mtod(m, struct mbuf *); 2644927Swnj n->m_off = ((int)p - (int)n) + off; 2655090Swnj mclrefcnt[mtocl(p)]++; 2668318Sroot } else 2674927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2684927Swnj (unsigned)n->m_len); 2695609Swnj if (len != M_COPYALL) 2705609Swnj len -= n->m_len; 2714927Swnj off = 0; 2724927Swnj m = m->m_next; 2734927Swnj np = &n->m_next; 2744927Swnj } 2754927Swnj return (top); 2764927Swnj nospace: 2774927Swnj m_freem(top); 2784927Swnj return (0); 2794927Swnj } 2804927Swnj 2814669Swnj m_cat(m, n) 2824669Swnj register struct mbuf *m, *n; 2834669Swnj { 2844669Swnj while (m->m_next) 2854669Swnj m = m->m_next; 2866091Sroot while (n) { 2876091Sroot if (m->m_off >= MMAXOFF || 2886091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2896091Sroot /* just join the two chains */ 2904669Swnj m->m_next = n; 2916091Sroot return; 2924669Swnj } 2936091Sroot /* splat the data from one into the other */ 2946091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 2956091Sroot (u_int)n->m_len); 2966091Sroot m->m_len += n->m_len; 2976091Sroot n = m_free(n); 2986091Sroot } 2994669Swnj } 3004669Swnj 3014585Swnj m_adj(mp, len) 3024585Swnj struct mbuf *mp; 3034916Swnj register int len; 3044585Swnj { 30524764Skarels register struct mbuf *m; 30624764Skarels register count; 3074585Swnj 3084585Swnj if ((m = mp) == NULL) 3094585Swnj return; 3104822Swnj if (len >= 0) { 3114585Swnj while (m != NULL && len > 0) { 3124822Swnj if (m->m_len <= len) { 3134585Swnj len -= m->m_len; 3144585Swnj m->m_len = 0; 3154585Swnj m = m->m_next; 3164822Swnj } else { 3174585Swnj m->m_len -= len; 3184585Swnj m->m_off += len; 3194585Swnj break; 3204585Swnj } 3214585Swnj } 3224822Swnj } else { 32324764Skarels /* 32424764Skarels * Trim from tail. Scan the mbuf chain, 32524764Skarels * calculating its length and finding the last mbuf. 32624764Skarels * If the adjustment only affects this mbuf, then just 32724764Skarels * adjust and return. Otherwise, rescan and truncate 32824764Skarels * after the remaining size. 32924764Skarels */ 3304585Swnj len = -len; 33124764Skarels count = 0; 33224764Skarels for (;;) { 33324764Skarels count += m->m_len; 33424764Skarels if (m->m_next == (struct mbuf *)0) 3354585Swnj break; 33624764Skarels m = m->m_next; 33724764Skarels } 33824764Skarels if (m->m_len >= len) { 33924764Skarels m->m_len -= len; 34024764Skarels return; 34124764Skarels } 34224764Skarels count -= len; 34324764Skarels /* 34424764Skarels * Correct length for chain is "count". 34524764Skarels * Find the mbuf with last data, adjust its length, 34624764Skarels * and toss data from remaining mbufs on chain. 34724764Skarels */ 34824764Skarels for (m = mp; m; m = m->m_next) { 34924764Skarels if (m->m_len >= count) { 35024764Skarels m->m_len = count; 35124764Skarels break; 3524585Swnj } 35324764Skarels count -= m->m_len; 3544585Swnj } 35524764Skarels while (m = m->m_next) 35624764Skarels m->m_len = 0; 3574585Swnj } 3584585Swnj } 3595228Swnj 36023816Skarels /* 36123816Skarels * Rearange an mbuf chain so that len bytes are contiguous 36223816Skarels * and in the data area of an mbuf (so that mtod and dtom 36324764Skarels * will work for a structure of size len). Returns the resulting 36424764Skarels * mbuf chain on success, frees it and returns null on failure. 36524764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 36624764Skarels * contiguous region in an attempt to avoid being called next time. 36723816Skarels */ 3685310Sroot struct mbuf * 36924764Skarels m_pullup(n, len) 37024764Skarels register struct mbuf *n; 3715228Swnj int len; 3725228Swnj { 37324764Skarels register struct mbuf *m; 37424764Skarels register int count; 37524764Skarels int space; 3765228Swnj 37724764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 37824764Skarels m = n; 37924764Skarels n = n->m_next; 38024764Skarels len -= m->m_len; 38124764Skarels } else { 38224764Skarels if (len > MLEN) 38324764Skarels goto bad; 38424764Skarels MGET(m, M_DONTWAIT, n->m_type); 38524764Skarels if (m == 0) 38624764Skarels goto bad; 38724764Skarels m->m_len = 0; 38824764Skarels } 38924764Skarels space = MMAXOFF - m->m_off; 3905310Sroot do { 39124764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 3926164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3936164Ssam (unsigned)count); 3946164Ssam len -= count; 3956164Ssam m->m_len += count; 3966164Ssam n->m_len -= count; 3975310Sroot if (n->m_len) 39823816Skarels n->m_off += count; 39923816Skarels else 40023816Skarels n = m_free(n); 40124764Skarels } while (len > 0 && n); 40224764Skarels if (len > 0) { 4035310Sroot (void) m_free(m); 4045310Sroot goto bad; 4055310Sroot } 4065310Sroot m->m_next = n; 4075310Sroot return (m); 4085310Sroot bad: 4095732Sroot m_freem(n); 4105228Swnj return (0); 4115228Swnj } 412