xref: /csrg-svn/sys/kern/uipc_mbuf.c (revision 24546)
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*24546Skarels  *	@(#)uipc_mbuf.c	6.7 (Berkeley) 09/05/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++;
167*24546Skarels 			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 {
2804585Swnj 	register struct mbuf *m, *n;
2814585Swnj 
2824585Swnj 	if ((m = mp) == NULL)
2834585Swnj 		return;
2844822Swnj 	if (len >= 0) {
2854585Swnj 		while (m != NULL && len > 0) {
2864822Swnj 			if (m->m_len <= len) {
2874585Swnj 				len -= m->m_len;
2884585Swnj 				m->m_len = 0;
2894585Swnj 				m = m->m_next;
2904822Swnj 			} else {
2914585Swnj 				m->m_len -= len;
2924585Swnj 				m->m_off += len;
2934585Swnj 				break;
2944585Swnj 			}
2954585Swnj 		}
2964822Swnj 	} else {
2974822Swnj 		/* a 2 pass algorithm might be better */
2984585Swnj 		len = -len;
2994585Swnj 		while (len > 0 && m->m_len != 0) {
3004585Swnj 			while (m != NULL && m->m_len != 0) {
3014585Swnj 				n = m;
3024585Swnj 				m = m->m_next;
3034585Swnj 			}
3044822Swnj 			if (n->m_len <= len) {
3054585Swnj 				len -= n->m_len;
3064585Swnj 				n->m_len = 0;
3074585Swnj 				m = mp;
3084822Swnj 			} else {
3094585Swnj 				n->m_len -= len;
3104585Swnj 				break;
3114585Swnj 			}
3124585Swnj 		}
3134585Swnj 	}
3144585Swnj }
3155228Swnj 
31623816Skarels /*
31723816Skarels  * Rearange an mbuf chain so that len bytes are contiguous
31823816Skarels  * and in the data area of an mbuf (so that mtod and dtom
31923816Skarels  * will work for a structure of size len).
32023816Skarels  * Returns the resulting mbuf chain on success,
32123816Skarels  * frees it and returns null on failure.
32223816Skarels  */
3235310Sroot struct mbuf *
3245310Sroot m_pullup(m0, len)
3255310Sroot 	struct mbuf *m0;
3265228Swnj 	int len;
3275228Swnj {
3285310Sroot 	register struct mbuf *m, *n;
3296164Ssam 	int count;
3305228Swnj 
3315732Sroot 	n = m0;
3325310Sroot 	if (len > MLEN)
3335310Sroot 		goto bad;
3349634Ssam 	MGET(m, M_DONTWAIT, n->m_type);
3355310Sroot 	if (m == 0)
3365310Sroot 		goto bad;
3375310Sroot 	m->m_len = 0;
3385310Sroot 	do {
33923816Skarels 		count = MIN(n->m_len, len);
3406164Ssam 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
3416164Ssam 		  (unsigned)count);
3426164Ssam 		len -= count;
3436164Ssam 		m->m_len += count;
3446164Ssam 		n->m_len -= count;
3455310Sroot 		if (n->m_len)
34623816Skarels 			n->m_off += count;
34723816Skarels 		else
34823816Skarels 			n = m_free(n);
34923816Skarels 	} while (len && n);
3505310Sroot 	if (len) {
3515310Sroot 		(void) m_free(m);
3525310Sroot 		goto bad;
3535310Sroot 	}
3545310Sroot 	m->m_next = n;
3555310Sroot 	return (m);
3565310Sroot bad:
3575732Sroot 	m_freem(n);
3585228Swnj 	return (0);
3595228Swnj }
360