123417Smckusick /* 233460Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 333185Sbostic * All rights reserved. 423417Smckusick * 533185Sbostic * Redistribution and use in source and binary forms are permitted 633185Sbostic * provided that this notice is preserved and that due credit is given 733185Sbostic * to the University of California at Berkeley. The name of the University 833185Sbostic * may not be used to endorse or promote products derived from this 933185Sbostic * software without specific prior written permission. This software 1033185Sbostic * is provided ``as is'' without express or implied warranty. 1133185Sbostic * 12*33606Skarels * @(#)uipc_mbuf.c 7.7 (Berkeley) 02/27/88 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 /* 230*33606Skarels /* 23121107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 23221107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23321107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 23421107Skarels */ 2354927Swnj struct mbuf * 2364927Swnj m_copy(m, off, len) 2374927Swnj register struct mbuf *m; 2384927Swnj int off; 2394927Swnj register int len; 2404927Swnj { 2414927Swnj register struct mbuf *n, **np; 2424927Swnj struct mbuf *top, *p; 2434927Swnj 2444927Swnj if (len == 0) 2454927Swnj return (0); 2464927Swnj if (off < 0 || len < 0) 2474927Swnj panic("m_copy"); 2484927Swnj while (off > 0) { 2494927Swnj if (m == 0) 2504927Swnj panic("m_copy"); 2514927Swnj if (off < m->m_len) 2524927Swnj break; 2534927Swnj off -= m->m_len; 2544927Swnj m = m->m_next; 2554927Swnj } 2564927Swnj np = ⊤ 2574927Swnj top = 0; 2584927Swnj while (len > 0) { 2595609Swnj if (m == 0) { 2605609Swnj if (len != M_COPYALL) 2615609Swnj panic("m_copy"); 2625609Swnj break; 2635609Swnj } 26421107Skarels MGET(n, M_DONTWAIT, m->m_type); 2654927Swnj *np = n; 2664927Swnj if (n == 0) 2674927Swnj goto nospace; 2684927Swnj n->m_len = MIN(len, m->m_len - off); 2694927Swnj if (m->m_off > MMAXOFF) { 2704927Swnj p = mtod(m, struct mbuf *); 2714927Swnj n->m_off = ((int)p - (int)n) + off; 2725090Swnj mclrefcnt[mtocl(p)]++; 2738318Sroot } else 2744927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2754927Swnj (unsigned)n->m_len); 2765609Swnj if (len != M_COPYALL) 2775609Swnj len -= n->m_len; 2784927Swnj off = 0; 2794927Swnj m = m->m_next; 2804927Swnj np = &n->m_next; 2814927Swnj } 2824927Swnj return (top); 2834927Swnj nospace: 2844927Swnj m_freem(top); 2854927Swnj return (0); 2864927Swnj } 2874927Swnj 288*33606Skarels /* 289*33606Skarels * Copy data from an mbuf chain starting "off" bytes from the beginning, 290*33606Skarels * continuing for "len" bytes, into the indicated buffer. 291*33606Skarels */ 292*33606Skarels struct mbuf * 293*33606Skarels m_copydata(m, off, len, cp) 294*33606Skarels register struct mbuf *m; 295*33606Skarels int off; 296*33606Skarels register int len; 297*33606Skarels caddr_t *cp; 298*33606Skarels { 299*33606Skarels register unsigned count; 300*33606Skarels 301*33606Skarels if (off < 0 || len < 0) 302*33606Skarels panic("m_copydata"); 303*33606Skarels while (off > 0) { 304*33606Skarels if (m == 0) 305*33606Skarels panic("m_copydata"); 306*33606Skarels if (off < m->m_len) 307*33606Skarels break; 308*33606Skarels off -= m->m_len; 309*33606Skarels m = m->m_next; 310*33606Skarels } 311*33606Skarels while (len > 0) { 312*33606Skarels if (m == 0) 313*33606Skarels panic("m_copydata"); 314*33606Skarels count = MIN(m->m_len, len); 315*33606Skarels bcopy(mtod(m, caddr_t) + off, cp, count); 316*33606Skarels len -= count; 317*33606Skarels off = 0; 318*33606Skarels m = m->m_next; 319*33606Skarels } 320*33606Skarels } 321*33606Skarels 3224669Swnj m_cat(m, n) 3234669Swnj register struct mbuf *m, *n; 3244669Swnj { 3254669Swnj while (m->m_next) 3264669Swnj m = m->m_next; 3276091Sroot while (n) { 3286091Sroot if (m->m_off >= MMAXOFF || 3296091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 3306091Sroot /* just join the two chains */ 3314669Swnj m->m_next = n; 3326091Sroot return; 3334669Swnj } 3346091Sroot /* splat the data from one into the other */ 3356091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3366091Sroot (u_int)n->m_len); 3376091Sroot m->m_len += n->m_len; 3386091Sroot n = m_free(n); 3396091Sroot } 3404669Swnj } 3414669Swnj 3424585Swnj m_adj(mp, len) 3434585Swnj struct mbuf *mp; 3444916Swnj register int len; 3454585Swnj { 34624764Skarels register struct mbuf *m; 34724764Skarels register count; 3484585Swnj 3494585Swnj if ((m = mp) == NULL) 3504585Swnj return; 3514822Swnj if (len >= 0) { 3524585Swnj while (m != NULL && len > 0) { 3534822Swnj if (m->m_len <= len) { 3544585Swnj len -= m->m_len; 3554585Swnj m->m_len = 0; 3564585Swnj m = m->m_next; 3574822Swnj } else { 3584585Swnj m->m_len -= len; 3594585Swnj m->m_off += len; 3604585Swnj break; 3614585Swnj } 3624585Swnj } 3634822Swnj } else { 36424764Skarels /* 36524764Skarels * Trim from tail. Scan the mbuf chain, 36624764Skarels * calculating its length and finding the last mbuf. 36724764Skarels * If the adjustment only affects this mbuf, then just 36824764Skarels * adjust and return. Otherwise, rescan and truncate 36924764Skarels * after the remaining size. 37024764Skarels */ 3714585Swnj len = -len; 37224764Skarels count = 0; 37324764Skarels for (;;) { 37424764Skarels count += m->m_len; 37524764Skarels if (m->m_next == (struct mbuf *)0) 3764585Swnj break; 37724764Skarels m = m->m_next; 37824764Skarels } 37924764Skarels if (m->m_len >= len) { 38024764Skarels m->m_len -= len; 38124764Skarels return; 38224764Skarels } 38324764Skarels count -= len; 38424764Skarels /* 38524764Skarels * Correct length for chain is "count". 38624764Skarels * Find the mbuf with last data, adjust its length, 38724764Skarels * and toss data from remaining mbufs on chain. 38824764Skarels */ 38924764Skarels for (m = mp; m; m = m->m_next) { 39024764Skarels if (m->m_len >= count) { 39124764Skarels m->m_len = count; 39224764Skarels break; 3934585Swnj } 39424764Skarels count -= m->m_len; 3954585Swnj } 39624764Skarels while (m = m->m_next) 39724764Skarels m->m_len = 0; 3984585Swnj } 3994585Swnj } 4005228Swnj 40123816Skarels /* 40223816Skarels * Rearange an mbuf chain so that len bytes are contiguous 40323816Skarels * and in the data area of an mbuf (so that mtod and dtom 40424764Skarels * will work for a structure of size len). Returns the resulting 40524764Skarels * mbuf chain on success, frees it and returns null on failure. 40624764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 40724764Skarels * contiguous region in an attempt to avoid being called next time. 40823816Skarels */ 4095310Sroot struct mbuf * 41024764Skarels m_pullup(n, len) 41124764Skarels register struct mbuf *n; 4125228Swnj int len; 4135228Swnj { 41424764Skarels register struct mbuf *m; 41524764Skarels register int count; 41624764Skarels int space; 4175228Swnj 41824764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 41924764Skarels m = n; 42024764Skarels n = n->m_next; 42124764Skarels len -= m->m_len; 42224764Skarels } else { 42324764Skarels if (len > MLEN) 42424764Skarels goto bad; 42524764Skarels MGET(m, M_DONTWAIT, n->m_type); 42624764Skarels if (m == 0) 42724764Skarels goto bad; 42824764Skarels m->m_len = 0; 42924764Skarels } 43024764Skarels space = MMAXOFF - m->m_off; 4315310Sroot do { 43224764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 4336164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 4346164Ssam (unsigned)count); 4356164Ssam len -= count; 4366164Ssam m->m_len += count; 4376164Ssam n->m_len -= count; 4385310Sroot if (n->m_len) 43923816Skarels n->m_off += count; 44023816Skarels else 44123816Skarels n = m_free(n); 44224764Skarels } while (len > 0 && n); 44324764Skarels if (len > 0) { 4445310Sroot (void) m_free(m); 4455310Sroot goto bad; 4465310Sroot } 4475310Sroot m->m_next = n; 4485310Sroot return (m); 4495310Sroot bad: 4505732Sroot m_freem(n); 4515228Swnj return (0); 4525228Swnj } 453