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*33988Skarels * @(#)uipc_mbuf.c 7.8 (Berkeley) 04/09/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); 199*33988Skarels if (mfree) 200*33988Skarels break; 20121107Skarels } else { 20221107Skarels mbstat.m_drops++; 20321107Skarels return (NULL); 20421107Skarels } 2054585Swnj } 2069634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 2079634Ssam MGET(m, canwait, type); 2085282Sroot #undef m_more 2094585Swnj return (m); 2104585Swnj } 2114585Swnj 2124669Swnj m_freem(m) 2134585Swnj register struct mbuf *m; 2144585Swnj { 2154585Swnj register struct mbuf *n; 2164927Swnj register int s; 2174585Swnj 2184585Swnj if (m == NULL) 2194916Swnj return; 2204662Swnj s = splimp(); 2214585Swnj do { 2224585Swnj MFREE(m, n); 2234585Swnj } while (m = n); 2244585Swnj splx(s); 2254585Swnj } 2264585Swnj 2275228Swnj /* 2285228Swnj * Mbuffer utility routines. 2295228Swnj */ 23021107Skarels 23121107Skarels /* 23233606Skarels /* 23321107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 23421107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23521107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 23621107Skarels */ 2374927Swnj struct mbuf * 2384927Swnj m_copy(m, off, len) 2394927Swnj register struct mbuf *m; 2404927Swnj int off; 2414927Swnj register int len; 2424927Swnj { 2434927Swnj register struct mbuf *n, **np; 2444927Swnj struct mbuf *top, *p; 2454927Swnj 2464927Swnj if (len == 0) 2474927Swnj return (0); 2484927Swnj if (off < 0 || len < 0) 2494927Swnj panic("m_copy"); 2504927Swnj while (off > 0) { 2514927Swnj if (m == 0) 2524927Swnj panic("m_copy"); 2534927Swnj if (off < m->m_len) 2544927Swnj break; 2554927Swnj off -= m->m_len; 2564927Swnj m = m->m_next; 2574927Swnj } 2584927Swnj np = ⊤ 2594927Swnj top = 0; 2604927Swnj while (len > 0) { 2615609Swnj if (m == 0) { 2625609Swnj if (len != M_COPYALL) 2635609Swnj panic("m_copy"); 2645609Swnj break; 2655609Swnj } 26621107Skarels MGET(n, M_DONTWAIT, m->m_type); 2674927Swnj *np = n; 2684927Swnj if (n == 0) 2694927Swnj goto nospace; 2704927Swnj n->m_len = MIN(len, m->m_len - off); 2714927Swnj if (m->m_off > MMAXOFF) { 2724927Swnj p = mtod(m, struct mbuf *); 2734927Swnj n->m_off = ((int)p - (int)n) + off; 2745090Swnj mclrefcnt[mtocl(p)]++; 2758318Sroot } else 2764927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2774927Swnj (unsigned)n->m_len); 2785609Swnj if (len != M_COPYALL) 2795609Swnj len -= n->m_len; 2804927Swnj off = 0; 2814927Swnj m = m->m_next; 2824927Swnj np = &n->m_next; 2834927Swnj } 2844927Swnj return (top); 2854927Swnj nospace: 2864927Swnj m_freem(top); 2874927Swnj return (0); 2884927Swnj } 2894927Swnj 29033606Skarels /* 29133606Skarels * Copy data from an mbuf chain starting "off" bytes from the beginning, 29233606Skarels * continuing for "len" bytes, into the indicated buffer. 29333606Skarels */ 29433606Skarels m_copydata(m, off, len, cp) 29533606Skarels register struct mbuf *m; 296*33988Skarels register int off; 29733606Skarels register int len; 298*33988Skarels caddr_t cp; 29933606Skarels { 30033606Skarels register unsigned count; 30133606Skarels 30233606Skarels if (off < 0 || len < 0) 30333606Skarels panic("m_copydata"); 30433606Skarels while (off > 0) { 30533606Skarels if (m == 0) 30633606Skarels panic("m_copydata"); 30733606Skarels if (off < m->m_len) 30833606Skarels break; 30933606Skarels off -= m->m_len; 31033606Skarels m = m->m_next; 31133606Skarels } 31233606Skarels while (len > 0) { 31333606Skarels if (m == 0) 31433606Skarels panic("m_copydata"); 315*33988Skarels count = MIN(m->m_len - off, len); 31633606Skarels bcopy(mtod(m, caddr_t) + off, cp, count); 31733606Skarels len -= count; 318*33988Skarels cp += count; 31933606Skarels off = 0; 32033606Skarels m = m->m_next; 32133606Skarels } 32233606Skarels } 32333606Skarels 3244669Swnj m_cat(m, n) 3254669Swnj register struct mbuf *m, *n; 3264669Swnj { 3274669Swnj while (m->m_next) 3284669Swnj m = m->m_next; 3296091Sroot while (n) { 3306091Sroot if (m->m_off >= MMAXOFF || 3316091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 3326091Sroot /* just join the two chains */ 3334669Swnj m->m_next = n; 3346091Sroot return; 3354669Swnj } 3366091Sroot /* splat the data from one into the other */ 3376091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3386091Sroot (u_int)n->m_len); 3396091Sroot m->m_len += n->m_len; 3406091Sroot n = m_free(n); 3416091Sroot } 3424669Swnj } 3434669Swnj 3444585Swnj m_adj(mp, len) 3454585Swnj struct mbuf *mp; 3464916Swnj register int len; 3474585Swnj { 34824764Skarels register struct mbuf *m; 34924764Skarels register count; 3504585Swnj 3514585Swnj if ((m = mp) == NULL) 3524585Swnj return; 3534822Swnj if (len >= 0) { 3544585Swnj while (m != NULL && len > 0) { 3554822Swnj if (m->m_len <= len) { 3564585Swnj len -= m->m_len; 3574585Swnj m->m_len = 0; 3584585Swnj m = m->m_next; 3594822Swnj } else { 3604585Swnj m->m_len -= len; 3614585Swnj m->m_off += len; 3624585Swnj break; 3634585Swnj } 3644585Swnj } 3654822Swnj } else { 36624764Skarels /* 36724764Skarels * Trim from tail. Scan the mbuf chain, 36824764Skarels * calculating its length and finding the last mbuf. 36924764Skarels * If the adjustment only affects this mbuf, then just 37024764Skarels * adjust and return. Otherwise, rescan and truncate 37124764Skarels * after the remaining size. 37224764Skarels */ 3734585Swnj len = -len; 37424764Skarels count = 0; 37524764Skarels for (;;) { 37624764Skarels count += m->m_len; 37724764Skarels if (m->m_next == (struct mbuf *)0) 3784585Swnj break; 37924764Skarels m = m->m_next; 38024764Skarels } 38124764Skarels if (m->m_len >= len) { 38224764Skarels m->m_len -= len; 38324764Skarels return; 38424764Skarels } 38524764Skarels count -= len; 38624764Skarels /* 38724764Skarels * Correct length for chain is "count". 38824764Skarels * Find the mbuf with last data, adjust its length, 38924764Skarels * and toss data from remaining mbufs on chain. 39024764Skarels */ 39124764Skarels for (m = mp; m; m = m->m_next) { 39224764Skarels if (m->m_len >= count) { 39324764Skarels m->m_len = count; 39424764Skarels break; 3954585Swnj } 39624764Skarels count -= m->m_len; 3974585Swnj } 39824764Skarels while (m = m->m_next) 39924764Skarels m->m_len = 0; 4004585Swnj } 4014585Swnj } 4025228Swnj 40323816Skarels /* 40423816Skarels * Rearange an mbuf chain so that len bytes are contiguous 40523816Skarels * and in the data area of an mbuf (so that mtod and dtom 40624764Skarels * will work for a structure of size len). Returns the resulting 40724764Skarels * mbuf chain on success, frees it and returns null on failure. 40824764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 40924764Skarels * contiguous region in an attempt to avoid being called next time. 41023816Skarels */ 4115310Sroot struct mbuf * 41224764Skarels m_pullup(n, len) 41324764Skarels register struct mbuf *n; 4145228Swnj int len; 4155228Swnj { 41624764Skarels register struct mbuf *m; 41724764Skarels register int count; 41824764Skarels int space; 4195228Swnj 42024764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 42124764Skarels m = n; 42224764Skarels n = n->m_next; 42324764Skarels len -= m->m_len; 42424764Skarels } else { 42524764Skarels if (len > MLEN) 42624764Skarels goto bad; 42724764Skarels MGET(m, M_DONTWAIT, n->m_type); 42824764Skarels if (m == 0) 42924764Skarels goto bad; 43024764Skarels m->m_len = 0; 43124764Skarels } 43224764Skarels space = MMAXOFF - m->m_off; 4335310Sroot do { 43424764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 4356164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 4366164Ssam (unsigned)count); 4376164Ssam len -= count; 4386164Ssam m->m_len += count; 4396164Ssam n->m_len -= count; 4405310Sroot if (n->m_len) 44123816Skarels n->m_off += count; 44223816Skarels else 44323816Skarels n = m_free(n); 44424764Skarels } while (len > 0 && n); 44524764Skarels if (len > 0) { 4465310Sroot (void) m_free(m); 4475310Sroot goto bad; 4485310Sroot } 4495310Sroot m->m_next = n; 4505310Sroot return (m); 4515310Sroot bad: 4525732Sroot m_freem(n); 4535228Swnj return (0); 4545228Swnj } 455