123417Smckusick /* 2*33460Skarels * 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*33460Skarels * @(#)uipc_mbuf.c 7.4.1.2 (Berkeley) 02/08/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; 103*33460Skarels 104*33460Skarels case MPG_SPACE: 105*33460Skarels mbstat.m_space++; 106*33460Skarels break; 1075228Swnj } 1085228Swnj return ((caddr_t)m); 1095228Swnj } 1105228Swnj 1115228Swnj m_pgfree(addr, n) 1125228Swnj caddr_t addr; 1135228Swnj int n; 1145228Swnj { 1155228Swnj 1166141Ssam #ifdef lint 1176141Ssam addr = addr; n = n; 1186141Ssam #endif 1195228Swnj } 1205228Swnj 12121107Skarels /* 12221107Skarels * Must be called at splimp. 12321107Skarels */ 12421107Skarels m_expand(canwait) 12521107Skarels int canwait; 1265228Swnj { 12730442Skarels register struct domain *dp; 12830442Skarels register struct protosw *pr; 12930442Skarels int tries; 1305228Swnj 13130442Skarels for (tries = 0;; ) { 13230442Skarels if (m_clalloc(1, MPG_MBUFS, canwait)) 13330442Skarels return (1); 13430442Skarels if (canwait == 0 || tries++) 13530442Skarels return (0); 13630442Skarels 13730442Skarels /* ask protocols to free space */ 13830442Skarels for (dp = domains; dp; dp = dp->dom_next) 13930442Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 14030442Skarels pr++) 14130442Skarels if (pr->pr_drain) 14230442Skarels (*pr->pr_drain)(); 14330442Skarels mbstat.m_drain++; 14430442Skarels } 1455228Swnj } 1465228Swnj 1475228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1485228Swnj 1495228Swnj /* 1505228Swnj * Space allocation routines. 1515228Swnj * These are also available as macros 1525228Swnj * for critical paths. 1535228Swnj */ 1544585Swnj struct mbuf * 1559634Ssam m_get(canwait, type) 1569634Ssam int canwait, type; 1574585Swnj { 1584585Swnj register struct mbuf *m; 1594585Swnj 1609634Ssam MGET(m, canwait, type); 1614585Swnj return (m); 1624585Swnj } 1634585Swnj 1644585Swnj struct mbuf * 1659634Ssam m_getclr(canwait, type) 1669634Ssam int canwait, type; 1674890Swnj { 1684890Swnj register struct mbuf *m; 1694890Swnj 17021107Skarels MGET(m, canwait, type); 1714890Swnj if (m == 0) 1724890Swnj return (0); 1734890Swnj bzero(mtod(m, caddr_t), MLEN); 1744890Swnj return (m); 1754890Swnj } 1764890Swnj 1774890Swnj struct mbuf * 1784585Swnj m_free(m) 1794585Swnj struct mbuf *m; 1804585Swnj { 1814585Swnj register struct mbuf *n; 1824585Swnj 1834585Swnj MFREE(m, n); 1844585Swnj return (n); 1854585Swnj } 1864585Swnj 18721107Skarels /* 18821107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 18921107Skarels * Must be called at splimp. 19021107Skarels */ 1914916Swnj /*ARGSUSED*/ 1924585Swnj struct mbuf * 1939634Ssam m_more(canwait, type) 1949634Ssam int canwait, type; 1954585Swnj { 1964585Swnj register struct mbuf *m; 1974585Swnj 19821107Skarels while (m_expand(canwait) == 0) { 19921107Skarels if (canwait == M_WAIT) { 20030442Skarels mbstat.m_wait++; 20121107Skarels m_want++; 20224546Skarels sleep((caddr_t)&mfree, PZERO - 1); 20321107Skarels } else { 20421107Skarels mbstat.m_drops++; 20521107Skarels return (NULL); 20621107Skarels } 2074585Swnj } 2089634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 2099634Ssam MGET(m, canwait, type); 2105282Sroot #undef m_more 2114585Swnj return (m); 2124585Swnj } 2134585Swnj 2144669Swnj m_freem(m) 2154585Swnj register struct mbuf *m; 2164585Swnj { 2174585Swnj register struct mbuf *n; 2184927Swnj register int s; 2194585Swnj 2204585Swnj if (m == NULL) 2214916Swnj return; 2224662Swnj s = splimp(); 2234585Swnj do { 2244585Swnj MFREE(m, n); 2254585Swnj } while (m = n); 2264585Swnj splx(s); 2274585Swnj } 2284585Swnj 2295228Swnj /* 2305228Swnj * Mbuffer utility routines. 2315228Swnj */ 23221107Skarels 23321107Skarels /* 23421107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 23521107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23621107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 23721107Skarels */ 2384927Swnj struct mbuf * 2394927Swnj m_copy(m, off, len) 2404927Swnj register struct mbuf *m; 2414927Swnj int off; 2424927Swnj register int len; 2434927Swnj { 2444927Swnj register struct mbuf *n, **np; 2454927Swnj struct mbuf *top, *p; 2464927Swnj 2474927Swnj if (len == 0) 2484927Swnj return (0); 2494927Swnj if (off < 0 || len < 0) 2504927Swnj panic("m_copy"); 2514927Swnj while (off > 0) { 2524927Swnj if (m == 0) 2534927Swnj panic("m_copy"); 2544927Swnj if (off < m->m_len) 2554927Swnj break; 2564927Swnj off -= m->m_len; 2574927Swnj m = m->m_next; 2584927Swnj } 2594927Swnj np = ⊤ 2604927Swnj top = 0; 2614927Swnj while (len > 0) { 2625609Swnj if (m == 0) { 2635609Swnj if (len != M_COPYALL) 2645609Swnj panic("m_copy"); 2655609Swnj break; 2665609Swnj } 26721107Skarels MGET(n, M_DONTWAIT, m->m_type); 2684927Swnj *np = n; 2694927Swnj if (n == 0) 2704927Swnj goto nospace; 2714927Swnj n->m_len = MIN(len, m->m_len - off); 2724927Swnj if (m->m_off > MMAXOFF) { 2734927Swnj p = mtod(m, struct mbuf *); 2744927Swnj n->m_off = ((int)p - (int)n) + off; 2755090Swnj mclrefcnt[mtocl(p)]++; 2768318Sroot } else 2774927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2784927Swnj (unsigned)n->m_len); 2795609Swnj if (len != M_COPYALL) 2805609Swnj len -= n->m_len; 2814927Swnj off = 0; 2824927Swnj m = m->m_next; 2834927Swnj np = &n->m_next; 2844927Swnj } 2854927Swnj return (top); 2864927Swnj nospace: 2874927Swnj m_freem(top); 2884927Swnj return (0); 2894927Swnj } 2904927Swnj 2914669Swnj m_cat(m, n) 2924669Swnj register struct mbuf *m, *n; 2934669Swnj { 2944669Swnj while (m->m_next) 2954669Swnj m = m->m_next; 2966091Sroot while (n) { 2976091Sroot if (m->m_off >= MMAXOFF || 2986091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2996091Sroot /* just join the two chains */ 3004669Swnj m->m_next = n; 3016091Sroot return; 3024669Swnj } 3036091Sroot /* splat the data from one into the other */ 3046091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3056091Sroot (u_int)n->m_len); 3066091Sroot m->m_len += n->m_len; 3076091Sroot n = m_free(n); 3086091Sroot } 3094669Swnj } 3104669Swnj 3114585Swnj m_adj(mp, len) 3124585Swnj struct mbuf *mp; 3134916Swnj register int len; 3144585Swnj { 31524764Skarels register struct mbuf *m; 31624764Skarels register count; 3174585Swnj 3184585Swnj if ((m = mp) == NULL) 3194585Swnj return; 3204822Swnj if (len >= 0) { 3214585Swnj while (m != NULL && len > 0) { 3224822Swnj if (m->m_len <= len) { 3234585Swnj len -= m->m_len; 3244585Swnj m->m_len = 0; 3254585Swnj m = m->m_next; 3264822Swnj } else { 3274585Swnj m->m_len -= len; 3284585Swnj m->m_off += len; 3294585Swnj break; 3304585Swnj } 3314585Swnj } 3324822Swnj } else { 33324764Skarels /* 33424764Skarels * Trim from tail. Scan the mbuf chain, 33524764Skarels * calculating its length and finding the last mbuf. 33624764Skarels * If the adjustment only affects this mbuf, then just 33724764Skarels * adjust and return. Otherwise, rescan and truncate 33824764Skarels * after the remaining size. 33924764Skarels */ 3404585Swnj len = -len; 34124764Skarels count = 0; 34224764Skarels for (;;) { 34324764Skarels count += m->m_len; 34424764Skarels if (m->m_next == (struct mbuf *)0) 3454585Swnj break; 34624764Skarels m = m->m_next; 34724764Skarels } 34824764Skarels if (m->m_len >= len) { 34924764Skarels m->m_len -= len; 35024764Skarels return; 35124764Skarels } 35224764Skarels count -= len; 35324764Skarels /* 35424764Skarels * Correct length for chain is "count". 35524764Skarels * Find the mbuf with last data, adjust its length, 35624764Skarels * and toss data from remaining mbufs on chain. 35724764Skarels */ 35824764Skarels for (m = mp; m; m = m->m_next) { 35924764Skarels if (m->m_len >= count) { 36024764Skarels m->m_len = count; 36124764Skarels break; 3624585Swnj } 36324764Skarels count -= m->m_len; 3644585Swnj } 36524764Skarels while (m = m->m_next) 36624764Skarels m->m_len = 0; 3674585Swnj } 3684585Swnj } 3695228Swnj 37023816Skarels /* 37123816Skarels * Rearange an mbuf chain so that len bytes are contiguous 37223816Skarels * and in the data area of an mbuf (so that mtod and dtom 37324764Skarels * will work for a structure of size len). Returns the resulting 37424764Skarels * mbuf chain on success, frees it and returns null on failure. 37524764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 37624764Skarels * contiguous region in an attempt to avoid being called next time. 37723816Skarels */ 3785310Sroot struct mbuf * 37924764Skarels m_pullup(n, len) 38024764Skarels register struct mbuf *n; 3815228Swnj int len; 3825228Swnj { 38324764Skarels register struct mbuf *m; 38424764Skarels register int count; 38524764Skarels int space; 3865228Swnj 38724764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 38824764Skarels m = n; 38924764Skarels n = n->m_next; 39024764Skarels len -= m->m_len; 39124764Skarels } else { 39224764Skarels if (len > MLEN) 39324764Skarels goto bad; 39424764Skarels MGET(m, M_DONTWAIT, n->m_type); 39524764Skarels if (m == 0) 39624764Skarels goto bad; 39724764Skarels m->m_len = 0; 39824764Skarels } 39924764Skarels space = MMAXOFF - m->m_off; 4005310Sroot do { 40124764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 4026164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 4036164Ssam (unsigned)count); 4046164Ssam len -= count; 4056164Ssam m->m_len += count; 4066164Ssam n->m_len -= count; 4075310Sroot if (n->m_len) 40823816Skarels n->m_off += count; 40923816Skarels else 41023816Skarels n = m_free(n); 41124764Skarels } while (len > 0 && n); 41224764Skarels if (len > 0) { 4135310Sroot (void) m_free(m); 4145310Sroot goto bad; 4155310Sroot } 4165310Sroot m->m_next = n; 4175310Sroot return (m); 4185310Sroot bad: 4195732Sroot m_freem(n); 4205228Swnj return (0); 4215228Swnj } 422