xref: /csrg-svn/sys/kern/uipc_mbuf.c (revision 24764)
123417Smckusick /*
223417Smckusick  * Copyright (c) 1982 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*24764Skarels  *	@(#)uipc_mbuf.c	6.8 (Berkeley) 09/16/85
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"
204585Swnj 
215228Swnj mbinit()
225228Swnj {
2321107Skarels 	int s;
245228Swnj 
2521107Skarels 	s = splimp();
2621107Skarels 	if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0)
275228Swnj 		goto bad;
2821107Skarels 	if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0)
295228Swnj 		goto bad;
3021107Skarels 	splx(s);
315228Swnj 	return;
325228Swnj bad:
335228Swnj 	panic("mbinit");
345228Swnj }
355228Swnj 
3621107Skarels /*
3721107Skarels  * Must be called at splimp.
3821107Skarels  */
395228Swnj caddr_t
4021107Skarels m_clalloc(ncl, how, canwait)
415228Swnj 	register int ncl;
425228Swnj 	int how;
435228Swnj {
445228Swnj 	int npg, mbx;
455228Swnj 	register struct mbuf *m;
465228Swnj 	register int i;
475228Swnj 
485228Swnj 	npg = ncl * CLSIZE;
498792Sroot 	mbx = rmalloc(mbmap, (long)npg);
5021107Skarels 	if (mbx == 0) {
5121107Skarels 		if (canwait == M_WAIT)
5221107Skarels 			panic("out of mbuf map");
535228Swnj 		return (0);
5421107Skarels 	}
555228Swnj 	m = cltom(mbx / CLSIZE);
569765Ssam 	if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
579765Ssam 		rmfree(mbmap, (long)npg, (long)mbx);
585228Swnj 		return (0);
599765Ssam 	}
605228Swnj 	vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
615228Swnj 	switch (how) {
625228Swnj 
635228Swnj 	case MPG_CLUSTERS:
645228Swnj 		for (i = 0; i < ncl; i++) {
655228Swnj 			m->m_off = 0;
665228Swnj 			m->m_next = mclfree;
675228Swnj 			mclfree = m;
685228Swnj 			m += CLBYTES / sizeof (*m);
696839Ssam 			mbstat.m_clfree++;
705228Swnj 		}
715228Swnj 		mbstat.m_clusters += ncl;
725228Swnj 		break;
735228Swnj 
745228Swnj 	case MPG_MBUFS:
755228Swnj 		for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
765228Swnj 			m->m_off = 0;
779634Ssam 			m->m_type = MT_DATA;
789634Ssam 			mbstat.m_mtypes[MT_DATA]++;
796839Ssam 			mbstat.m_mbufs++;
805228Swnj 			(void) m_free(m);
815228Swnj 			m++;
825228Swnj 		}
835232Swnj 		break;
845228Swnj 	}
855228Swnj 	return ((caddr_t)m);
865228Swnj }
875228Swnj 
885228Swnj m_pgfree(addr, n)
895228Swnj 	caddr_t addr;
905228Swnj 	int n;
915228Swnj {
925228Swnj 
936141Ssam #ifdef lint
946141Ssam 	addr = addr; n = n;
956141Ssam #endif
965228Swnj }
975228Swnj 
9821107Skarels /*
9921107Skarels  * Must be called at splimp.
10021107Skarels  */
10121107Skarels m_expand(canwait)
10221107Skarels 	int canwait;
1035228Swnj {
1045228Swnj 
10521107Skarels 	if (m_clalloc(1, MPG_MBUFS, canwait) == 0)
1065228Swnj 		goto steal;
1075228Swnj 	return (1);
1085228Swnj steal:
1095228Swnj 	/* should ask protocols to free code */
1105228Swnj 	return (0);
1115228Swnj }
1125228Swnj 
1135228Swnj /* NEED SOME WAY TO RELEASE SPACE */
1145228Swnj 
1155228Swnj /*
1165228Swnj  * Space allocation routines.
1175228Swnj  * These are also available as macros
1185228Swnj  * for critical paths.
1195228Swnj  */
1204585Swnj struct mbuf *
1219634Ssam m_get(canwait, type)
1229634Ssam 	int canwait, type;
1234585Swnj {
1244585Swnj 	register struct mbuf *m;
1254585Swnj 
1269634Ssam 	MGET(m, canwait, type);
1274585Swnj 	return (m);
1284585Swnj }
1294585Swnj 
1304585Swnj struct mbuf *
1319634Ssam m_getclr(canwait, type)
1329634Ssam 	int canwait, type;
1334890Swnj {
1344890Swnj 	register struct mbuf *m;
1354890Swnj 
13621107Skarels 	MGET(m, canwait, type);
1374890Swnj 	if (m == 0)
1384890Swnj 		return (0);
1394890Swnj 	bzero(mtod(m, caddr_t), MLEN);
1404890Swnj 	return (m);
1414890Swnj }
1424890Swnj 
1434890Swnj struct mbuf *
1444585Swnj m_free(m)
1454585Swnj 	struct mbuf *m;
1464585Swnj {
1474585Swnj 	register struct mbuf *n;
1484585Swnj 
1494585Swnj 	MFREE(m, n);
1504585Swnj 	return (n);
1514585Swnj }
1524585Swnj 
15321107Skarels /*
15421107Skarels  * Get more mbufs; called from MGET macro if mfree list is empty.
15521107Skarels  * Must be called at splimp.
15621107Skarels  */
1574916Swnj /*ARGSUSED*/
1584585Swnj struct mbuf *
1599634Ssam m_more(canwait, type)
1609634Ssam 	int canwait, type;
1614585Swnj {
1624585Swnj 	register struct mbuf *m;
1634585Swnj 
16421107Skarels 	while (m_expand(canwait) == 0) {
16521107Skarels 		if (canwait == M_WAIT) {
16621107Skarels 			m_want++;
16724546Skarels 			sleep((caddr_t)&mfree, PZERO - 1);
16821107Skarels 		} else {
16921107Skarels 			mbstat.m_drops++;
17021107Skarels 			return (NULL);
17121107Skarels 		}
1724585Swnj 	}
1739634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
1749634Ssam 	MGET(m, canwait, type);
1755282Sroot #undef m_more
1764585Swnj 	return (m);
1774585Swnj }
1784585Swnj 
1794669Swnj m_freem(m)
1804585Swnj 	register struct mbuf *m;
1814585Swnj {
1824585Swnj 	register struct mbuf *n;
1834927Swnj 	register int s;
1844585Swnj 
1854585Swnj 	if (m == NULL)
1864916Swnj 		return;
1874662Swnj 	s = splimp();
1884585Swnj 	do {
1894585Swnj 		MFREE(m, n);
1904585Swnj 	} while (m = n);
1914585Swnj 	splx(s);
1924585Swnj }
1934585Swnj 
1945228Swnj /*
1955228Swnj  * Mbuffer utility routines.
1965228Swnj  */
19721107Skarels 
19821107Skarels /*
19921107Skarels  * Make a copy of an mbuf chain starting "off" bytes from the beginning,
20021107Skarels  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
20121107Skarels  * Should get M_WAIT/M_DONTWAIT from caller.
20221107Skarels  */
2034927Swnj struct mbuf *
2044927Swnj m_copy(m, off, len)
2054927Swnj 	register struct mbuf *m;
2064927Swnj 	int off;
2074927Swnj 	register int len;
2084927Swnj {
2094927Swnj 	register struct mbuf *n, **np;
2104927Swnj 	struct mbuf *top, *p;
2114927Swnj 
2124927Swnj 	if (len == 0)
2134927Swnj 		return (0);
2144927Swnj 	if (off < 0 || len < 0)
2154927Swnj 		panic("m_copy");
2164927Swnj 	while (off > 0) {
2174927Swnj 		if (m == 0)
2184927Swnj 			panic("m_copy");
2194927Swnj 		if (off < m->m_len)
2204927Swnj 			break;
2214927Swnj 		off -= m->m_len;
2224927Swnj 		m = m->m_next;
2234927Swnj 	}
2244927Swnj 	np = &top;
2254927Swnj 	top = 0;
2264927Swnj 	while (len > 0) {
2275609Swnj 		if (m == 0) {
2285609Swnj 			if (len != M_COPYALL)
2295609Swnj 				panic("m_copy");
2305609Swnj 			break;
2315609Swnj 		}
23221107Skarels 		MGET(n, M_DONTWAIT, m->m_type);
2334927Swnj 		*np = n;
2344927Swnj 		if (n == 0)
2354927Swnj 			goto nospace;
2364927Swnj 		n->m_len = MIN(len, m->m_len - off);
2374927Swnj 		if (m->m_off > MMAXOFF) {
2384927Swnj 			p = mtod(m, struct mbuf *);
2394927Swnj 			n->m_off = ((int)p - (int)n) + off;
2405090Swnj 			mclrefcnt[mtocl(p)]++;
2418318Sroot 		} else
2424927Swnj 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
2434927Swnj 			    (unsigned)n->m_len);
2445609Swnj 		if (len != M_COPYALL)
2455609Swnj 			len -= n->m_len;
2464927Swnj 		off = 0;
2474927Swnj 		m = m->m_next;
2484927Swnj 		np = &n->m_next;
2494927Swnj 	}
2504927Swnj 	return (top);
2514927Swnj nospace:
2524927Swnj 	m_freem(top);
2534927Swnj 	return (0);
2544927Swnj }
2554927Swnj 
2564669Swnj m_cat(m, n)
2574669Swnj 	register struct mbuf *m, *n;
2584669Swnj {
2594669Swnj 	while (m->m_next)
2604669Swnj 		m = m->m_next;
2616091Sroot 	while (n) {
2626091Sroot 		if (m->m_off >= MMAXOFF ||
2636091Sroot 		    m->m_off + m->m_len + n->m_len > MMAXOFF) {
2646091Sroot 			/* just join the two chains */
2654669Swnj 			m->m_next = n;
2666091Sroot 			return;
2674669Swnj 		}
2686091Sroot 		/* splat the data from one into the other */
2696091Sroot 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
2706091Sroot 		    (u_int)n->m_len);
2716091Sroot 		m->m_len += n->m_len;
2726091Sroot 		n = m_free(n);
2736091Sroot 	}
2744669Swnj }
2754669Swnj 
2764585Swnj m_adj(mp, len)
2774585Swnj 	struct mbuf *mp;
2784916Swnj 	register int len;
2794585Swnj {
280*24764Skarels 	register struct mbuf *m;
281*24764Skarels 	register count;
2824585Swnj 
2834585Swnj 	if ((m = mp) == NULL)
2844585Swnj 		return;
2854822Swnj 	if (len >= 0) {
2864585Swnj 		while (m != NULL && len > 0) {
2874822Swnj 			if (m->m_len <= len) {
2884585Swnj 				len -= m->m_len;
2894585Swnj 				m->m_len = 0;
2904585Swnj 				m = m->m_next;
2914822Swnj 			} else {
2924585Swnj 				m->m_len -= len;
2934585Swnj 				m->m_off += len;
2944585Swnj 				break;
2954585Swnj 			}
2964585Swnj 		}
2974822Swnj 	} else {
298*24764Skarels 		/*
299*24764Skarels 		 * Trim from tail.  Scan the mbuf chain,
300*24764Skarels 		 * calculating its length and finding the last mbuf.
301*24764Skarels 		 * If the adjustment only affects this mbuf, then just
302*24764Skarels 		 * adjust and return.  Otherwise, rescan and truncate
303*24764Skarels 		 * after the remaining size.
304*24764Skarels 		 */
3054585Swnj 		len = -len;
306*24764Skarels 		count = 0;
307*24764Skarels 		for (;;) {
308*24764Skarels 			count += m->m_len;
309*24764Skarels 			if (m->m_next == (struct mbuf *)0)
3104585Swnj 				break;
311*24764Skarels 			m = m->m_next;
312*24764Skarels 		}
313*24764Skarels 		if (m->m_len >= len) {
314*24764Skarels 			m->m_len -= len;
315*24764Skarels 			return;
316*24764Skarels 		}
317*24764Skarels 		count -= len;
318*24764Skarels 		/*
319*24764Skarels 		 * Correct length for chain is "count".
320*24764Skarels 		 * Find the mbuf with last data, adjust its length,
321*24764Skarels 		 * and toss data from remaining mbufs on chain.
322*24764Skarels 		 */
323*24764Skarels 		for (m = mp; m; m = m->m_next) {
324*24764Skarels 			if (m->m_len >= count) {
325*24764Skarels 				m->m_len = count;
326*24764Skarels 				break;
3274585Swnj 			}
328*24764Skarels 			count -= m->m_len;
3294585Swnj 		}
330*24764Skarels 		while (m = m->m_next)
331*24764Skarels 			m->m_len = 0;
3324585Swnj 	}
3334585Swnj }
3345228Swnj 
33523816Skarels /*
33623816Skarels  * Rearange an mbuf chain so that len bytes are contiguous
33723816Skarels  * and in the data area of an mbuf (so that mtod and dtom
338*24764Skarels  * will work for a structure of size len).  Returns the resulting
339*24764Skarels  * mbuf chain on success, frees it and returns null on failure.
340*24764Skarels  * If there is room, it will add up to MPULL_EXTRA bytes to the
341*24764Skarels  * contiguous region in an attempt to avoid being called next time.
34223816Skarels  */
3435310Sroot struct mbuf *
344*24764Skarels m_pullup(n, len)
345*24764Skarels 	register struct mbuf *n;
3465228Swnj 	int len;
3475228Swnj {
348*24764Skarels 	register struct mbuf *m;
349*24764Skarels 	register int count;
350*24764Skarels 	int space;
3515228Swnj 
352*24764Skarels 	if (n->m_off + len <= MMAXOFF && n->m_next) {
353*24764Skarels 		m = n;
354*24764Skarels 		n = n->m_next;
355*24764Skarels 		len -= m->m_len;
356*24764Skarels 	} else {
357*24764Skarels 		if (len > MLEN)
358*24764Skarels 			goto bad;
359*24764Skarels 		MGET(m, M_DONTWAIT, n->m_type);
360*24764Skarels 		if (m == 0)
361*24764Skarels 			goto bad;
362*24764Skarels 		m->m_len = 0;
363*24764Skarels 	}
364*24764Skarels 	space = MMAXOFF - m->m_off;
3655310Sroot 	do {
366*24764Skarels 		count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len);
3676164Ssam 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
3686164Ssam 		  (unsigned)count);
3696164Ssam 		len -= count;
3706164Ssam 		m->m_len += count;
3716164Ssam 		n->m_len -= count;
3725310Sroot 		if (n->m_len)
37323816Skarels 			n->m_off += count;
37423816Skarels 		else
37523816Skarels 			n = m_free(n);
376*24764Skarels 	} while (len > 0 && n);
377*24764Skarels 	if (len > 0) {
3785310Sroot 		(void) m_free(m);
3795310Sroot 		goto bad;
3805310Sroot 	}
3815310Sroot 	m->m_next = n;
3825310Sroot 	return (m);
3835310Sroot bad:
3845732Sroot 	m_freem(n);
3855228Swnj 	return (0);
3865228Swnj }
387