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*30442Skarels * @(#)uipc_mbuf.c 7.2 (Berkeley) 02/02/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" 20*30442Skarels #include "syslog.h" 21*30442Skarels #include "domain.h" 22*30442Skarels #include "protosw.h" 234585Swnj 245228Swnj mbinit() 255228Swnj { 2621107Skarels int s; 275228Swnj 2821107Skarels s = splimp(); 2921107Skarels if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0) 305228Swnj goto bad; 3128938Skarels if (m_clalloc(4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0) 325228Swnj goto bad; 3321107Skarels splx(s); 345228Swnj return; 355228Swnj bad: 365228Swnj panic("mbinit"); 375228Swnj } 385228Swnj 3921107Skarels /* 4021107Skarels * Must be called at splimp. 4121107Skarels */ 42*30442Skarels /* ARGSUSED */ 435228Swnj caddr_t 4421107Skarels m_clalloc(ncl, how, canwait) 455228Swnj register int ncl; 465228Swnj int how; 475228Swnj { 485228Swnj int npg, mbx; 495228Swnj register struct mbuf *m; 505228Swnj register int i; 51*30442Skarels static int logged; 525228Swnj 535228Swnj npg = ncl * CLSIZE; 548792Sroot mbx = rmalloc(mbmap, (long)npg); 5521107Skarels if (mbx == 0) { 56*30442Skarels if (logged == 0) { 57*30442Skarels logged++; 58*30442Skarels log(LOG_ERR, "mbuf map full\n"); 59*30442Skarels } 605228Swnj return (0); 6121107Skarels } 625228Swnj m = cltom(mbx / CLSIZE); 639765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 649765Ssam rmfree(mbmap, (long)npg, (long)mbx); 655228Swnj return (0); 669765Ssam } 675228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 685228Swnj switch (how) { 695228Swnj 705228Swnj case MPG_CLUSTERS: 715228Swnj for (i = 0; i < ncl; i++) { 725228Swnj m->m_off = 0; 735228Swnj m->m_next = mclfree; 745228Swnj mclfree = m; 755228Swnj m += CLBYTES / sizeof (*m); 766839Ssam mbstat.m_clfree++; 775228Swnj } 785228Swnj mbstat.m_clusters += ncl; 795228Swnj break; 805228Swnj 815228Swnj case MPG_MBUFS: 825228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 835228Swnj m->m_off = 0; 849634Ssam m->m_type = MT_DATA; 859634Ssam mbstat.m_mtypes[MT_DATA]++; 866839Ssam mbstat.m_mbufs++; 875228Swnj (void) m_free(m); 885228Swnj m++; 895228Swnj } 905232Swnj break; 91*30442Skarels 92*30442Skarels case MPG_SPACE: 93*30442Skarels mbstat.m_space++; 94*30442Skarels break; 955228Swnj } 965228Swnj return ((caddr_t)m); 975228Swnj } 985228Swnj 995228Swnj m_pgfree(addr, n) 1005228Swnj caddr_t addr; 1015228Swnj int n; 1025228Swnj { 1035228Swnj 1046141Ssam #ifdef lint 1056141Ssam addr = addr; n = n; 1066141Ssam #endif 1075228Swnj } 1085228Swnj 10921107Skarels /* 11021107Skarels * Must be called at splimp. 11121107Skarels */ 11221107Skarels m_expand(canwait) 11321107Skarels int canwait; 1145228Swnj { 115*30442Skarels register struct domain *dp; 116*30442Skarels register struct protosw *pr; 117*30442Skarels int tries; 1185228Swnj 119*30442Skarels for (tries = 0;; ) { 120*30442Skarels if (m_clalloc(1, MPG_MBUFS, canwait)) 121*30442Skarels return (1); 122*30442Skarels if (canwait == 0 || tries++) 123*30442Skarels return (0); 124*30442Skarels 125*30442Skarels /* ask protocols to free space */ 126*30442Skarels for (dp = domains; dp; dp = dp->dom_next) 127*30442Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 128*30442Skarels pr++) 129*30442Skarels if (pr->pr_drain) 130*30442Skarels (*pr->pr_drain)(); 131*30442Skarels mbstat.m_drain++; 132*30442Skarels } 1335228Swnj } 1345228Swnj 1355228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1365228Swnj 1375228Swnj /* 1385228Swnj * Space allocation routines. 1395228Swnj * These are also available as macros 1405228Swnj * for critical paths. 1415228Swnj */ 1424585Swnj struct mbuf * 1439634Ssam m_get(canwait, type) 1449634Ssam int canwait, type; 1454585Swnj { 1464585Swnj register struct mbuf *m; 1474585Swnj 1489634Ssam MGET(m, canwait, type); 1494585Swnj return (m); 1504585Swnj } 1514585Swnj 1524585Swnj struct mbuf * 1539634Ssam m_getclr(canwait, type) 1549634Ssam int canwait, type; 1554890Swnj { 1564890Swnj register struct mbuf *m; 1574890Swnj 15821107Skarels MGET(m, canwait, type); 1594890Swnj if (m == 0) 1604890Swnj return (0); 1614890Swnj bzero(mtod(m, caddr_t), MLEN); 1624890Swnj return (m); 1634890Swnj } 1644890Swnj 1654890Swnj struct mbuf * 1664585Swnj m_free(m) 1674585Swnj struct mbuf *m; 1684585Swnj { 1694585Swnj register struct mbuf *n; 1704585Swnj 1714585Swnj MFREE(m, n); 1724585Swnj return (n); 1734585Swnj } 1744585Swnj 17521107Skarels /* 17621107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 17721107Skarels * Must be called at splimp. 17821107Skarels */ 1794916Swnj /*ARGSUSED*/ 1804585Swnj struct mbuf * 1819634Ssam m_more(canwait, type) 1829634Ssam int canwait, type; 1834585Swnj { 1844585Swnj register struct mbuf *m; 1854585Swnj 18621107Skarels while (m_expand(canwait) == 0) { 18721107Skarels if (canwait == M_WAIT) { 188*30442Skarels mbstat.m_wait++; 18921107Skarels m_want++; 19024546Skarels sleep((caddr_t)&mfree, PZERO - 1); 19121107Skarels } else { 19221107Skarels mbstat.m_drops++; 19321107Skarels return (NULL); 19421107Skarels } 1954585Swnj } 1969634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 1979634Ssam MGET(m, canwait, type); 1985282Sroot #undef m_more 1994585Swnj return (m); 2004585Swnj } 2014585Swnj 2024669Swnj m_freem(m) 2034585Swnj register struct mbuf *m; 2044585Swnj { 2054585Swnj register struct mbuf *n; 2064927Swnj register int s; 2074585Swnj 2084585Swnj if (m == NULL) 2094916Swnj return; 2104662Swnj s = splimp(); 2114585Swnj do { 2124585Swnj MFREE(m, n); 2134585Swnj } while (m = n); 2144585Swnj splx(s); 2154585Swnj } 2164585Swnj 2175228Swnj /* 2185228Swnj * Mbuffer utility routines. 2195228Swnj */ 22021107Skarels 22121107Skarels /* 22221107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 22321107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 22421107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 22521107Skarels */ 2264927Swnj struct mbuf * 2274927Swnj m_copy(m, off, len) 2284927Swnj register struct mbuf *m; 2294927Swnj int off; 2304927Swnj register int len; 2314927Swnj { 2324927Swnj register struct mbuf *n, **np; 2334927Swnj struct mbuf *top, *p; 2344927Swnj 2354927Swnj if (len == 0) 2364927Swnj return (0); 2374927Swnj if (off < 0 || len < 0) 2384927Swnj panic("m_copy"); 2394927Swnj while (off > 0) { 2404927Swnj if (m == 0) 2414927Swnj panic("m_copy"); 2424927Swnj if (off < m->m_len) 2434927Swnj break; 2444927Swnj off -= m->m_len; 2454927Swnj m = m->m_next; 2464927Swnj } 2474927Swnj np = ⊤ 2484927Swnj top = 0; 2494927Swnj while (len > 0) { 2505609Swnj if (m == 0) { 2515609Swnj if (len != M_COPYALL) 2525609Swnj panic("m_copy"); 2535609Swnj break; 2545609Swnj } 25521107Skarels MGET(n, M_DONTWAIT, m->m_type); 2564927Swnj *np = n; 2574927Swnj if (n == 0) 2584927Swnj goto nospace; 2594927Swnj n->m_len = MIN(len, m->m_len - off); 2604927Swnj if (m->m_off > MMAXOFF) { 2614927Swnj p = mtod(m, struct mbuf *); 2624927Swnj n->m_off = ((int)p - (int)n) + off; 2635090Swnj mclrefcnt[mtocl(p)]++; 2648318Sroot } else 2654927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2664927Swnj (unsigned)n->m_len); 2675609Swnj if (len != M_COPYALL) 2685609Swnj len -= n->m_len; 2694927Swnj off = 0; 2704927Swnj m = m->m_next; 2714927Swnj np = &n->m_next; 2724927Swnj } 2734927Swnj return (top); 2744927Swnj nospace: 2754927Swnj m_freem(top); 2764927Swnj return (0); 2774927Swnj } 2784927Swnj 2794669Swnj m_cat(m, n) 2804669Swnj register struct mbuf *m, *n; 2814669Swnj { 2824669Swnj while (m->m_next) 2834669Swnj m = m->m_next; 2846091Sroot while (n) { 2856091Sroot if (m->m_off >= MMAXOFF || 2866091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 2876091Sroot /* just join the two chains */ 2884669Swnj m->m_next = n; 2896091Sroot return; 2904669Swnj } 2916091Sroot /* splat the data from one into the other */ 2926091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 2936091Sroot (u_int)n->m_len); 2946091Sroot m->m_len += n->m_len; 2956091Sroot n = m_free(n); 2966091Sroot } 2974669Swnj } 2984669Swnj 2994585Swnj m_adj(mp, len) 3004585Swnj struct mbuf *mp; 3014916Swnj register int len; 3024585Swnj { 30324764Skarels register struct mbuf *m; 30424764Skarels register count; 3054585Swnj 3064585Swnj if ((m = mp) == NULL) 3074585Swnj return; 3084822Swnj if (len >= 0) { 3094585Swnj while (m != NULL && len > 0) { 3104822Swnj if (m->m_len <= len) { 3114585Swnj len -= m->m_len; 3124585Swnj m->m_len = 0; 3134585Swnj m = m->m_next; 3144822Swnj } else { 3154585Swnj m->m_len -= len; 3164585Swnj m->m_off += len; 3174585Swnj break; 3184585Swnj } 3194585Swnj } 3204822Swnj } else { 32124764Skarels /* 32224764Skarels * Trim from tail. Scan the mbuf chain, 32324764Skarels * calculating its length and finding the last mbuf. 32424764Skarels * If the adjustment only affects this mbuf, then just 32524764Skarels * adjust and return. Otherwise, rescan and truncate 32624764Skarels * after the remaining size. 32724764Skarels */ 3284585Swnj len = -len; 32924764Skarels count = 0; 33024764Skarels for (;;) { 33124764Skarels count += m->m_len; 33224764Skarels if (m->m_next == (struct mbuf *)0) 3334585Swnj break; 33424764Skarels m = m->m_next; 33524764Skarels } 33624764Skarels if (m->m_len >= len) { 33724764Skarels m->m_len -= len; 33824764Skarels return; 33924764Skarels } 34024764Skarels count -= len; 34124764Skarels /* 34224764Skarels * Correct length for chain is "count". 34324764Skarels * Find the mbuf with last data, adjust its length, 34424764Skarels * and toss data from remaining mbufs on chain. 34524764Skarels */ 34624764Skarels for (m = mp; m; m = m->m_next) { 34724764Skarels if (m->m_len >= count) { 34824764Skarels m->m_len = count; 34924764Skarels break; 3504585Swnj } 35124764Skarels count -= m->m_len; 3524585Swnj } 35324764Skarels while (m = m->m_next) 35424764Skarels m->m_len = 0; 3554585Swnj } 3564585Swnj } 3575228Swnj 35823816Skarels /* 35923816Skarels * Rearange an mbuf chain so that len bytes are contiguous 36023816Skarels * and in the data area of an mbuf (so that mtod and dtom 36124764Skarels * will work for a structure of size len). Returns the resulting 36224764Skarels * mbuf chain on success, frees it and returns null on failure. 36324764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 36424764Skarels * contiguous region in an attempt to avoid being called next time. 36523816Skarels */ 3665310Sroot struct mbuf * 36724764Skarels m_pullup(n, len) 36824764Skarels register struct mbuf *n; 3695228Swnj int len; 3705228Swnj { 37124764Skarels register struct mbuf *m; 37224764Skarels register int count; 37324764Skarels int space; 3745228Swnj 37524764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 37624764Skarels m = n; 37724764Skarels n = n->m_next; 37824764Skarels len -= m->m_len; 37924764Skarels } else { 38024764Skarels if (len > MLEN) 38124764Skarels goto bad; 38224764Skarels MGET(m, M_DONTWAIT, n->m_type); 38324764Skarels if (m == 0) 38424764Skarels goto bad; 38524764Skarels m->m_len = 0; 38624764Skarels } 38724764Skarels space = MMAXOFF - m->m_off; 3885310Sroot do { 38924764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 3906164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 3916164Ssam (unsigned)count); 3926164Ssam len -= count; 3936164Ssam m->m_len += count; 3946164Ssam n->m_len -= count; 3955310Sroot if (n->m_len) 39623816Skarels n->m_off += count; 39723816Skarels else 39823816Skarels n = m_free(n); 39924764Skarels } while (len > 0 && n); 40024764Skarels if (len > 0) { 4015310Sroot (void) m_free(m); 4025310Sroot goto bad; 4035310Sroot } 4045310Sroot m->m_next = n; 4055310Sroot return (m); 4065310Sroot bad: 4075732Sroot m_freem(n); 4085228Swnj return (0); 4095228Swnj } 410