123417Smckusick /* 229124Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*33185Sbostic * All rights reserved. 423417Smckusick * 5*33185Sbostic * Redistribution and use in source and binary forms are permitted 6*33185Sbostic * provided that this notice is preserved and that due credit is given 7*33185Sbostic * to the University of California at Berkeley. The name of the University 8*33185Sbostic * may not be used to endorse or promote products derived from this 9*33185Sbostic * software without specific prior written permission. This software 10*33185Sbostic * is provided ``as is'' without express or implied warranty. 11*33185Sbostic * 12*33185Sbostic * @(#)uipc_mbuf.c 7.5 (Berkeley) 12/30/87 1323417Smckusick */ 144585Swnj 159765Ssam #include "../machine/pte.h" 169765Ssam 1717102Sbloom #include "param.h" 1817102Sbloom #include "dir.h" 1917102Sbloom #include "user.h" 2017102Sbloom #include "proc.h" 2117102Sbloom #include "cmap.h" 2217102Sbloom #include "map.h" 2317102Sbloom #include "mbuf.h" 2417102Sbloom #include "vm.h" 2517102Sbloom #include "kernel.h" 2630442Skarels #include "syslog.h" 2730442Skarels #include "domain.h" 2830442Skarels #include "protosw.h" 294585Swnj 305228Swnj mbinit() 315228Swnj { 3221107Skarels int s; 335228Swnj 3432659Skarels #if CLBYTES < 4096 3532659Skarels #define NCL_INIT (4096/CLBYTES) 3632659Skarels #else 3732659Skarels #define NCL_INIT 1 3832659Skarels #endif 3921107Skarels s = splimp(); 4032659Skarels if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0) 415228Swnj goto bad; 4232659Skarels if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0) 435228Swnj goto bad; 4421107Skarels splx(s); 455228Swnj return; 465228Swnj bad: 475228Swnj panic("mbinit"); 485228Swnj } 495228Swnj 5021107Skarels /* 5121107Skarels * Must be called at splimp. 5221107Skarels */ 5330442Skarels /* ARGSUSED */ 545228Swnj caddr_t 5521107Skarels m_clalloc(ncl, how, canwait) 565228Swnj register int ncl; 575228Swnj int how; 585228Swnj { 595228Swnj int npg, mbx; 605228Swnj register struct mbuf *m; 615228Swnj register int i; 6230442Skarels static int logged; 635228Swnj 645228Swnj npg = ncl * CLSIZE; 658792Sroot mbx = rmalloc(mbmap, (long)npg); 6621107Skarels if (mbx == 0) { 6730442Skarels if (logged == 0) { 6830442Skarels logged++; 6930442Skarels log(LOG_ERR, "mbuf map full\n"); 7030442Skarels } 715228Swnj return (0); 7221107Skarels } 7332659Skarels m = cltom(mbx * NBPG / MCLBYTES); 749765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 759765Ssam rmfree(mbmap, (long)npg, (long)mbx); 765228Swnj return (0); 779765Ssam } 785228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 795228Swnj switch (how) { 805228Swnj 815228Swnj case MPG_CLUSTERS: 8232659Skarels ncl = ncl * CLBYTES / MCLBYTES; 835228Swnj for (i = 0; i < ncl; i++) { 845228Swnj m->m_off = 0; 855228Swnj m->m_next = mclfree; 865228Swnj mclfree = m; 8732659Skarels m += MCLBYTES / sizeof (*m); 886839Ssam mbstat.m_clfree++; 895228Swnj } 905228Swnj mbstat.m_clusters += ncl; 915228Swnj break; 925228Swnj 935228Swnj case MPG_MBUFS: 945228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 955228Swnj m->m_off = 0; 969634Ssam m->m_type = MT_DATA; 979634Ssam mbstat.m_mtypes[MT_DATA]++; 986839Ssam mbstat.m_mbufs++; 995228Swnj (void) m_free(m); 1005228Swnj m++; 1015228Swnj } 1025232Swnj break; 1035228Swnj } 1045228Swnj return ((caddr_t)m); 1055228Swnj } 1065228Swnj 1075228Swnj m_pgfree(addr, n) 1085228Swnj caddr_t addr; 1095228Swnj int n; 1105228Swnj { 1115228Swnj 1126141Ssam #ifdef lint 1136141Ssam addr = addr; n = n; 1146141Ssam #endif 1155228Swnj } 1165228Swnj 11721107Skarels /* 11821107Skarels * Must be called at splimp. 11921107Skarels */ 12021107Skarels m_expand(canwait) 12121107Skarels int canwait; 1225228Swnj { 12330442Skarels register struct domain *dp; 12430442Skarels register struct protosw *pr; 12530442Skarels int tries; 1265228Swnj 12730442Skarels for (tries = 0;; ) { 12830442Skarels if (m_clalloc(1, MPG_MBUFS, canwait)) 12930442Skarels return (1); 13030442Skarels if (canwait == 0 || tries++) 13130442Skarels return (0); 13230442Skarels 13330442Skarels /* ask protocols to free space */ 13430442Skarels for (dp = domains; dp; dp = dp->dom_next) 13530442Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 13630442Skarels pr++) 13730442Skarels if (pr->pr_drain) 13830442Skarels (*pr->pr_drain)(); 13930442Skarels mbstat.m_drain++; 14030442Skarels } 1415228Swnj } 1425228Swnj 1435228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1445228Swnj 1455228Swnj /* 1465228Swnj * Space allocation routines. 1475228Swnj * These are also available as macros 1485228Swnj * for critical paths. 1495228Swnj */ 1504585Swnj struct mbuf * 1519634Ssam m_get(canwait, type) 1529634Ssam int canwait, type; 1534585Swnj { 1544585Swnj register struct mbuf *m; 1554585Swnj 1569634Ssam MGET(m, canwait, type); 1574585Swnj return (m); 1584585Swnj } 1594585Swnj 1604585Swnj struct mbuf * 1619634Ssam m_getclr(canwait, type) 1629634Ssam int canwait, type; 1634890Swnj { 1644890Swnj register struct mbuf *m; 1654890Swnj 16621107Skarels MGET(m, canwait, type); 1674890Swnj if (m == 0) 1684890Swnj return (0); 1694890Swnj bzero(mtod(m, caddr_t), MLEN); 1704890Swnj return (m); 1714890Swnj } 1724890Swnj 1734890Swnj struct mbuf * 1744585Swnj m_free(m) 1754585Swnj struct mbuf *m; 1764585Swnj { 1774585Swnj register struct mbuf *n; 1784585Swnj 1794585Swnj MFREE(m, n); 1804585Swnj return (n); 1814585Swnj } 1824585Swnj 18321107Skarels /* 18421107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 18521107Skarels * Must be called at splimp. 18621107Skarels */ 1874916Swnj /*ARGSUSED*/ 1884585Swnj struct mbuf * 1899634Ssam m_more(canwait, type) 1909634Ssam int canwait, type; 1914585Swnj { 1924585Swnj register struct mbuf *m; 1934585Swnj 19421107Skarels while (m_expand(canwait) == 0) { 19521107Skarels if (canwait == M_WAIT) { 19630442Skarels mbstat.m_wait++; 19721107Skarels m_want++; 19824546Skarels sleep((caddr_t)&mfree, PZERO - 1); 19921107Skarels } else { 20021107Skarels mbstat.m_drops++; 20121107Skarels return (NULL); 20221107Skarels } 2034585Swnj } 2049634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 2059634Ssam MGET(m, canwait, type); 2065282Sroot #undef m_more 2074585Swnj return (m); 2084585Swnj } 2094585Swnj 2104669Swnj m_freem(m) 2114585Swnj register struct mbuf *m; 2124585Swnj { 2134585Swnj register struct mbuf *n; 2144927Swnj register int s; 2154585Swnj 2164585Swnj if (m == NULL) 2174916Swnj return; 2184662Swnj s = splimp(); 2194585Swnj do { 2204585Swnj MFREE(m, n); 2214585Swnj } while (m = n); 2224585Swnj splx(s); 2234585Swnj } 2244585Swnj 2255228Swnj /* 2265228Swnj * Mbuffer utility routines. 2275228Swnj */ 22821107Skarels 22921107Skarels /* 23021107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 23121107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23221107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 23321107Skarels */ 2344927Swnj struct mbuf * 2354927Swnj m_copy(m, off, len) 2364927Swnj register struct mbuf *m; 2374927Swnj int off; 2384927Swnj register int len; 2394927Swnj { 2404927Swnj register struct mbuf *n, **np; 2414927Swnj struct mbuf *top, *p; 2424927Swnj 2434927Swnj if (len == 0) 2444927Swnj return (0); 2454927Swnj if (off < 0 || len < 0) 2464927Swnj panic("m_copy"); 2474927Swnj while (off > 0) { 2484927Swnj if (m == 0) 2494927Swnj panic("m_copy"); 2504927Swnj if (off < m->m_len) 2514927Swnj break; 2524927Swnj off -= m->m_len; 2534927Swnj m = m->m_next; 2544927Swnj } 2554927Swnj np = ⊤ 2564927Swnj top = 0; 2574927Swnj while (len > 0) { 2585609Swnj if (m == 0) { 2595609Swnj if (len != M_COPYALL) 2605609Swnj panic("m_copy"); 2615609Swnj break; 2625609Swnj } 26321107Skarels MGET(n, M_DONTWAIT, m->m_type); 2644927Swnj *np = n; 2654927Swnj if (n == 0) 2664927Swnj goto nospace; 2674927Swnj n->m_len = MIN(len, m->m_len - off); 2684927Swnj if (m->m_off > MMAXOFF) { 2694927Swnj p = mtod(m, struct mbuf *); 2704927Swnj n->m_off = ((int)p - (int)n) + off; 2715090Swnj mclrefcnt[mtocl(p)]++; 2728318Sroot } else 2734927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2744927Swnj (unsigned)n->m_len); 2755609Swnj if (len != M_COPYALL) 2765609Swnj len -= n->m_len; 2774927Swnj off = 0; 2784927Swnj m = m->m_next; 2794927Swnj np = &n->m_next; 2804927Swnj } 2814927Swnj return (top); 2824927Swnj nospace: 2834927Swnj m_freem(top); 2844927Swnj return (0); 2854927Swnj } 2864927Swnj 2874669Swnj m_cat(m, n) 2884669Swnj register struct mbuf *m, *n; 2894669Swnj { 2904669Swnj while (m->m_next) 2914669Swnj m = m->m_next; 2926091Sroot while (n) { 2936091Sroot if (m->m_off >= MMAXOFF || 2946091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2956091Sroot /* just join the two chains */ 2964669Swnj m->m_next = n; 2976091Sroot return; 2984669Swnj } 2996091Sroot /* splat the data from one into the other */ 3006091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3016091Sroot (u_int)n->m_len); 3026091Sroot m->m_len += n->m_len; 3036091Sroot n = m_free(n); 3046091Sroot } 3054669Swnj } 3064669Swnj 3074585Swnj m_adj(mp, len) 3084585Swnj struct mbuf *mp; 3094916Swnj register int len; 3104585Swnj { 31124764Skarels register struct mbuf *m; 31224764Skarels register count; 3134585Swnj 3144585Swnj if ((m = mp) == NULL) 3154585Swnj return; 3164822Swnj if (len >= 0) { 3174585Swnj while (m != NULL && len > 0) { 3184822Swnj if (m->m_len <= len) { 3194585Swnj len -= m->m_len; 3204585Swnj m->m_len = 0; 3214585Swnj m = m->m_next; 3224822Swnj } else { 3234585Swnj m->m_len -= len; 3244585Swnj m->m_off += len; 3254585Swnj break; 3264585Swnj } 3274585Swnj } 3284822Swnj } else { 32924764Skarels /* 33024764Skarels * Trim from tail. Scan the mbuf chain, 33124764Skarels * calculating its length and finding the last mbuf. 33224764Skarels * If the adjustment only affects this mbuf, then just 33324764Skarels * adjust and return. Otherwise, rescan and truncate 33424764Skarels * after the remaining size. 33524764Skarels */ 3364585Swnj len = -len; 33724764Skarels count = 0; 33824764Skarels for (;;) { 33924764Skarels count += m->m_len; 34024764Skarels if (m->m_next == (struct mbuf *)0) 3414585Swnj break; 34224764Skarels m = m->m_next; 34324764Skarels } 34424764Skarels if (m->m_len >= len) { 34524764Skarels m->m_len -= len; 34624764Skarels return; 34724764Skarels } 34824764Skarels count -= len; 34924764Skarels /* 35024764Skarels * Correct length for chain is "count". 35124764Skarels * Find the mbuf with last data, adjust its length, 35224764Skarels * and toss data from remaining mbufs on chain. 35324764Skarels */ 35424764Skarels for (m = mp; m; m = m->m_next) { 35524764Skarels if (m->m_len >= count) { 35624764Skarels m->m_len = count; 35724764Skarels break; 3584585Swnj } 35924764Skarels count -= m->m_len; 3604585Swnj } 36124764Skarels while (m = m->m_next) 36224764Skarels m->m_len = 0; 3634585Swnj } 3644585Swnj } 3655228Swnj 36623816Skarels /* 36723816Skarels * Rearange an mbuf chain so that len bytes are contiguous 36823816Skarels * and in the data area of an mbuf (so that mtod and dtom 36924764Skarels * will work for a structure of size len). Returns the resulting 37024764Skarels * mbuf chain on success, frees it and returns null on failure. 37124764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 37224764Skarels * contiguous region in an attempt to avoid being called next time. 37323816Skarels */ 3745310Sroot struct mbuf * 37524764Skarels m_pullup(n, len) 37624764Skarels register struct mbuf *n; 3775228Swnj int len; 3785228Swnj { 37924764Skarels register struct mbuf *m; 38024764Skarels register int count; 38124764Skarels int space; 3825228Swnj 38324764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 38424764Skarels m = n; 38524764Skarels n = n->m_next; 38624764Skarels len -= m->m_len; 38724764Skarels } else { 38824764Skarels if (len > MLEN) 38924764Skarels goto bad; 39024764Skarels MGET(m, M_DONTWAIT, n->m_type); 39124764Skarels if (m == 0) 39224764Skarels goto bad; 39324764Skarels m->m_len = 0; 39424764Skarels } 39524764Skarels space = MMAXOFF - m->m_off; 3965310Sroot do { 39724764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 3986164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3996164Ssam (unsigned)count); 4006164Ssam len -= count; 4016164Ssam m->m_len += count; 4026164Ssam n->m_len -= count; 4035310Sroot if (n->m_len) 40423816Skarels n->m_off += count; 40523816Skarels else 40623816Skarels n = m_free(n); 40724764Skarels } while (len > 0 && n); 40824764Skarels if (len > 0) { 4095310Sroot (void) m_free(m); 4105310Sroot goto bad; 4115310Sroot } 4125310Sroot m->m_next = n; 4135310Sroot return (m); 4145310Sroot bad: 4155732Sroot m_freem(n); 4165228Swnj return (0); 4175228Swnj } 418