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 6*34860Sbostic * provided that the above copyright notice and this paragraph are 7*34860Sbostic * duplicated in all such forms and that any documentation, 8*34860Sbostic * advertising materials, and other materials related to such 9*34860Sbostic * distribution and use acknowledge that the software was developed 10*34860Sbostic * by the University of California, Berkeley. The name of the 11*34860Sbostic * University may not be used to endorse or promote products derived 12*34860Sbostic * from this software without specific prior written permission. 13*34860Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34860Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34860Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633185Sbostic * 17*34860Sbostic * @(#)uipc_mbuf.c 7.10 (Berkeley) 06/29/88 1823417Smckusick */ 194585Swnj 209765Ssam #include "../machine/pte.h" 219765Ssam 2217102Sbloom #include "param.h" 2317102Sbloom #include "dir.h" 2417102Sbloom #include "user.h" 2517102Sbloom #include "proc.h" 2617102Sbloom #include "cmap.h" 2717102Sbloom #include "map.h" 2817102Sbloom #include "mbuf.h" 2917102Sbloom #include "vm.h" 3017102Sbloom #include "kernel.h" 3130442Skarels #include "syslog.h" 3230442Skarels #include "domain.h" 3330442Skarels #include "protosw.h" 344585Swnj 355228Swnj mbinit() 365228Swnj { 3721107Skarels int s; 385228Swnj 3932659Skarels #if CLBYTES < 4096 4032659Skarels #define NCL_INIT (4096/CLBYTES) 4132659Skarels #else 4232659Skarels #define NCL_INIT 1 4332659Skarels #endif 4421107Skarels s = splimp(); 4532659Skarels if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0) 465228Swnj goto bad; 4732659Skarels if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0) 485228Swnj goto bad; 4921107Skarels splx(s); 505228Swnj return; 515228Swnj bad: 525228Swnj panic("mbinit"); 535228Swnj } 545228Swnj 5521107Skarels /* 5621107Skarels * Must be called at splimp. 5721107Skarels */ 5830442Skarels /* ARGSUSED */ 595228Swnj caddr_t 6021107Skarels m_clalloc(ncl, how, canwait) 615228Swnj register int ncl; 625228Swnj int how; 635228Swnj { 645228Swnj int npg, mbx; 655228Swnj register struct mbuf *m; 665228Swnj register int i; 6730442Skarels static int logged; 685228Swnj 695228Swnj npg = ncl * CLSIZE; 708792Sroot mbx = rmalloc(mbmap, (long)npg); 7121107Skarels if (mbx == 0) { 7230442Skarels if (logged == 0) { 7330442Skarels logged++; 7430442Skarels log(LOG_ERR, "mbuf map full\n"); 7530442Skarels } 765228Swnj return (0); 7721107Skarels } 7832659Skarels m = cltom(mbx * NBPG / MCLBYTES); 799765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 809765Ssam rmfree(mbmap, (long)npg, (long)mbx); 815228Swnj return (0); 829765Ssam } 835228Swnj vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 845228Swnj switch (how) { 855228Swnj 865228Swnj case MPG_CLUSTERS: 8732659Skarels ncl = ncl * CLBYTES / MCLBYTES; 885228Swnj for (i = 0; i < ncl; i++) { 895228Swnj m->m_off = 0; 905228Swnj m->m_next = mclfree; 915228Swnj mclfree = m; 9232659Skarels m += MCLBYTES / sizeof (*m); 936839Ssam mbstat.m_clfree++; 945228Swnj } 955228Swnj mbstat.m_clusters += ncl; 965228Swnj break; 975228Swnj 985228Swnj case MPG_MBUFS: 995228Swnj for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 1005228Swnj m->m_off = 0; 1019634Ssam m->m_type = MT_DATA; 1029634Ssam mbstat.m_mtypes[MT_DATA]++; 1036839Ssam mbstat.m_mbufs++; 1045228Swnj (void) m_free(m); 1055228Swnj m++; 1065228Swnj } 1075232Swnj break; 1085228Swnj } 1095228Swnj return ((caddr_t)m); 1105228Swnj } 1115228Swnj 11221107Skarels /* 11321107Skarels * Must be called at splimp. 11421107Skarels */ 11521107Skarels m_expand(canwait) 11621107Skarels int canwait; 1175228Swnj { 11830442Skarels register struct domain *dp; 11930442Skarels register struct protosw *pr; 12030442Skarels int tries; 1215228Swnj 12230442Skarels for (tries = 0;; ) { 12330442Skarels if (m_clalloc(1, MPG_MBUFS, canwait)) 12430442Skarels return (1); 12530442Skarels if (canwait == 0 || tries++) 12630442Skarels return (0); 12730442Skarels 12830442Skarels /* ask protocols to free space */ 12930442Skarels for (dp = domains; dp; dp = dp->dom_next) 13030442Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 13130442Skarels pr++) 13230442Skarels if (pr->pr_drain) 13330442Skarels (*pr->pr_drain)(); 13430442Skarels mbstat.m_drain++; 13530442Skarels } 1365228Swnj } 1375228Swnj 1385228Swnj /* NEED SOME WAY TO RELEASE SPACE */ 1395228Swnj 1405228Swnj /* 1415228Swnj * Space allocation routines. 1425228Swnj * These are also available as macros 1435228Swnj * for critical paths. 1445228Swnj */ 1454585Swnj struct mbuf * 1469634Ssam m_get(canwait, type) 1479634Ssam int canwait, type; 1484585Swnj { 1494585Swnj register struct mbuf *m; 1504585Swnj 1519634Ssam MGET(m, canwait, type); 1524585Swnj return (m); 1534585Swnj } 1544585Swnj 1554585Swnj struct mbuf * 1569634Ssam m_getclr(canwait, type) 1579634Ssam int canwait, type; 1584890Swnj { 1594890Swnj register struct mbuf *m; 1604890Swnj 16121107Skarels MGET(m, canwait, type); 1624890Swnj if (m == 0) 1634890Swnj return (0); 1644890Swnj bzero(mtod(m, caddr_t), MLEN); 1654890Swnj return (m); 1664890Swnj } 1674890Swnj 1684890Swnj struct mbuf * 1694585Swnj m_free(m) 1704585Swnj struct mbuf *m; 1714585Swnj { 1724585Swnj register struct mbuf *n; 1734585Swnj 1744585Swnj MFREE(m, n); 1754585Swnj return (n); 1764585Swnj } 1774585Swnj 17821107Skarels /* 17921107Skarels * Get more mbufs; called from MGET macro if mfree list is empty. 18021107Skarels * Must be called at splimp. 18121107Skarels */ 1824916Swnj /*ARGSUSED*/ 1834585Swnj struct mbuf * 1849634Ssam m_more(canwait, type) 1859634Ssam int canwait, type; 1864585Swnj { 1874585Swnj register struct mbuf *m; 1884585Swnj 18921107Skarels while (m_expand(canwait) == 0) { 19021107Skarels if (canwait == M_WAIT) { 19130442Skarels mbstat.m_wait++; 19221107Skarels m_want++; 19324546Skarels sleep((caddr_t)&mfree, PZERO - 1); 19433988Skarels if (mfree) 19533988Skarels break; 19621107Skarels } else { 19721107Skarels mbstat.m_drops++; 19821107Skarels return (NULL); 19921107Skarels } 2004585Swnj } 2019634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 2029634Ssam MGET(m, canwait, type); 2035282Sroot #undef m_more 2044585Swnj return (m); 2054585Swnj } 2064585Swnj 2074669Swnj m_freem(m) 2084585Swnj register struct mbuf *m; 2094585Swnj { 2104585Swnj register struct mbuf *n; 2114927Swnj register int s; 2124585Swnj 2134585Swnj if (m == NULL) 2144916Swnj return; 2154662Swnj s = splimp(); 2164585Swnj do { 2174585Swnj MFREE(m, n); 2184585Swnj } while (m = n); 2194585Swnj splx(s); 2204585Swnj } 2214585Swnj 2225228Swnj /* 2235228Swnj * Mbuffer utility routines. 2245228Swnj */ 22521107Skarels 22621107Skarels /* 22733606Skarels /* 22821107Skarels * Make a copy of an mbuf chain starting "off" bytes from the beginning, 22921107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23021107Skarels * Should get M_WAIT/M_DONTWAIT from caller. 23121107Skarels */ 2324927Swnj struct mbuf * 2334927Swnj m_copy(m, off, len) 2344927Swnj register struct mbuf *m; 2354927Swnj int off; 2364927Swnj register int len; 2374927Swnj { 2384927Swnj register struct mbuf *n, **np; 2394927Swnj struct mbuf *top, *p; 2404927Swnj 2414927Swnj if (len == 0) 2424927Swnj return (0); 2434927Swnj if (off < 0 || len < 0) 2444927Swnj panic("m_copy"); 2454927Swnj while (off > 0) { 2464927Swnj if (m == 0) 2474927Swnj panic("m_copy"); 2484927Swnj if (off < m->m_len) 2494927Swnj break; 2504927Swnj off -= m->m_len; 2514927Swnj m = m->m_next; 2524927Swnj } 2534927Swnj np = ⊤ 2544927Swnj top = 0; 2554927Swnj while (len > 0) { 2565609Swnj if (m == 0) { 2575609Swnj if (len != M_COPYALL) 2585609Swnj panic("m_copy"); 2595609Swnj break; 2605609Swnj } 26121107Skarels MGET(n, M_DONTWAIT, m->m_type); 2624927Swnj *np = n; 2634927Swnj if (n == 0) 2644927Swnj goto nospace; 2654927Swnj n->m_len = MIN(len, m->m_len - off); 2664927Swnj if (m->m_off > MMAXOFF) { 2674927Swnj p = mtod(m, struct mbuf *); 2684927Swnj n->m_off = ((int)p - (int)n) + off; 2695090Swnj mclrefcnt[mtocl(p)]++; 2708318Sroot } else 2714927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2724927Swnj (unsigned)n->m_len); 2735609Swnj if (len != M_COPYALL) 2745609Swnj len -= n->m_len; 2754927Swnj off = 0; 2764927Swnj m = m->m_next; 2774927Swnj np = &n->m_next; 2784927Swnj } 2794927Swnj return (top); 2804927Swnj nospace: 2814927Swnj m_freem(top); 2824927Swnj return (0); 2834927Swnj } 2844927Swnj 28533606Skarels /* 28633606Skarels * Copy data from an mbuf chain starting "off" bytes from the beginning, 28733606Skarels * continuing for "len" bytes, into the indicated buffer. 28833606Skarels */ 28933606Skarels m_copydata(m, off, len, cp) 29033606Skarels register struct mbuf *m; 29133988Skarels register int off; 29233606Skarels register int len; 29333988Skarels caddr_t cp; 29433606Skarels { 29533606Skarels register unsigned count; 29633606Skarels 29733606Skarels if (off < 0 || len < 0) 29833606Skarels panic("m_copydata"); 29933606Skarels while (off > 0) { 30033606Skarels if (m == 0) 30133606Skarels panic("m_copydata"); 30233606Skarels if (off < m->m_len) 30333606Skarels break; 30433606Skarels off -= m->m_len; 30533606Skarels m = m->m_next; 30633606Skarels } 30733606Skarels while (len > 0) { 30833606Skarels if (m == 0) 30933606Skarels panic("m_copydata"); 31033988Skarels count = MIN(m->m_len - off, len); 31133606Skarels bcopy(mtod(m, caddr_t) + off, cp, count); 31233606Skarels len -= count; 31333988Skarels cp += count; 31433606Skarels off = 0; 31533606Skarels m = m->m_next; 31633606Skarels } 31733606Skarels } 31833606Skarels 3194669Swnj m_cat(m, n) 3204669Swnj register struct mbuf *m, *n; 3214669Swnj { 3224669Swnj while (m->m_next) 3234669Swnj m = m->m_next; 3246091Sroot while (n) { 3256091Sroot if (m->m_off >= MMAXOFF || 3266091Sroot m->m_off + m->m_len + n->m_len > MMAXOFF) { 3276091Sroot /* just join the two chains */ 3284669Swnj m->m_next = n; 3296091Sroot return; 3304669Swnj } 3316091Sroot /* splat the data from one into the other */ 3326091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3336091Sroot (u_int)n->m_len); 3346091Sroot m->m_len += n->m_len; 3356091Sroot n = m_free(n); 3366091Sroot } 3374669Swnj } 3384669Swnj 3394585Swnj m_adj(mp, len) 3404585Swnj struct mbuf *mp; 3414916Swnj register int len; 3424585Swnj { 34324764Skarels register struct mbuf *m; 34424764Skarels register count; 3454585Swnj 3464585Swnj if ((m = mp) == NULL) 3474585Swnj return; 3484822Swnj if (len >= 0) { 3494585Swnj while (m != NULL && len > 0) { 3504822Swnj if (m->m_len <= len) { 3514585Swnj len -= m->m_len; 3524585Swnj m->m_len = 0; 3534585Swnj m = m->m_next; 3544822Swnj } else { 3554585Swnj m->m_len -= len; 3564585Swnj m->m_off += len; 3574585Swnj break; 3584585Swnj } 3594585Swnj } 3604822Swnj } else { 36124764Skarels /* 36224764Skarels * Trim from tail. Scan the mbuf chain, 36324764Skarels * calculating its length and finding the last mbuf. 36424764Skarels * If the adjustment only affects this mbuf, then just 36524764Skarels * adjust and return. Otherwise, rescan and truncate 36624764Skarels * after the remaining size. 36724764Skarels */ 3684585Swnj len = -len; 36924764Skarels count = 0; 37024764Skarels for (;;) { 37124764Skarels count += m->m_len; 37224764Skarels if (m->m_next == (struct mbuf *)0) 3734585Swnj break; 37424764Skarels m = m->m_next; 37524764Skarels } 37624764Skarels if (m->m_len >= len) { 37724764Skarels m->m_len -= len; 37824764Skarels return; 37924764Skarels } 38024764Skarels count -= len; 38124764Skarels /* 38224764Skarels * Correct length for chain is "count". 38324764Skarels * Find the mbuf with last data, adjust its length, 38424764Skarels * and toss data from remaining mbufs on chain. 38524764Skarels */ 38624764Skarels for (m = mp; m; m = m->m_next) { 38724764Skarels if (m->m_len >= count) { 38824764Skarels m->m_len = count; 38924764Skarels break; 3904585Swnj } 39124764Skarels count -= m->m_len; 3924585Swnj } 39324764Skarels while (m = m->m_next) 39424764Skarels m->m_len = 0; 3954585Swnj } 3964585Swnj } 3975228Swnj 39823816Skarels /* 39923816Skarels * Rearange an mbuf chain so that len bytes are contiguous 40023816Skarels * and in the data area of an mbuf (so that mtod and dtom 40124764Skarels * will work for a structure of size len). Returns the resulting 40224764Skarels * mbuf chain on success, frees it and returns null on failure. 40324764Skarels * If there is room, it will add up to MPULL_EXTRA bytes to the 40424764Skarels * contiguous region in an attempt to avoid being called next time. 40523816Skarels */ 4065310Sroot struct mbuf * 40724764Skarels m_pullup(n, len) 40824764Skarels register struct mbuf *n; 4095228Swnj int len; 4105228Swnj { 41124764Skarels register struct mbuf *m; 41224764Skarels register int count; 41324764Skarels int space; 4145228Swnj 41524764Skarels if (n->m_off + len <= MMAXOFF && n->m_next) { 41624764Skarels m = n; 41724764Skarels n = n->m_next; 41824764Skarels len -= m->m_len; 41924764Skarels } else { 42024764Skarels if (len > MLEN) 42124764Skarels goto bad; 42224764Skarels MGET(m, M_DONTWAIT, n->m_type); 42324764Skarels if (m == 0) 42424764Skarels goto bad; 42524764Skarels m->m_len = 0; 42624764Skarels } 42724764Skarels space = MMAXOFF - m->m_off; 4285310Sroot do { 42924764Skarels count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 4306164Ssam bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 4316164Ssam (unsigned)count); 4326164Ssam len -= count; 4336164Ssam m->m_len += count; 4346164Ssam n->m_len -= count; 4355310Sroot if (n->m_len) 43623816Skarels n->m_off += count; 43723816Skarels else 43823816Skarels n = m_free(n); 43924764Skarels } while (len > 0 && n); 44024764Skarels if (len > 0) { 4415310Sroot (void) m_free(m); 4425310Sroot goto bad; 4435310Sroot } 4445310Sroot m->m_next = n; 4455310Sroot return (m); 4465310Sroot bad: 4475732Sroot m_freem(n); 4485228Swnj return (0); 4495228Swnj } 450