xref: /csrg-svn/sys/kern/uipc_mbuf.c (revision 21107)
1*21107Skarels /*	uipc_mbuf.c	6.4	85/05/27	*/
24585Swnj 
39765Ssam #include "../machine/pte.h"
49765Ssam 
517102Sbloom #include "param.h"
617102Sbloom #include "dir.h"
717102Sbloom #include "user.h"
817102Sbloom #include "proc.h"
917102Sbloom #include "cmap.h"
1017102Sbloom #include "map.h"
1117102Sbloom #include "mbuf.h"
1217102Sbloom #include "vm.h"
1317102Sbloom #include "kernel.h"
144585Swnj 
155228Swnj mbinit()
165228Swnj {
17*21107Skarels 	int s;
185228Swnj 
19*21107Skarels 	s = splimp();
20*21107Skarels 	if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0)
215228Swnj 		goto bad;
22*21107Skarels 	if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0)
235228Swnj 		goto bad;
24*21107Skarels 	splx(s);
255228Swnj 	return;
265228Swnj bad:
275228Swnj 	panic("mbinit");
285228Swnj }
295228Swnj 
30*21107Skarels /*
31*21107Skarels  * Must be called at splimp.
32*21107Skarels  */
335228Swnj caddr_t
34*21107Skarels m_clalloc(ncl, how, canwait)
355228Swnj 	register int ncl;
365228Swnj 	int how;
375228Swnj {
385228Swnj 	int npg, mbx;
395228Swnj 	register struct mbuf *m;
405228Swnj 	register int i;
415228Swnj 
425228Swnj 	npg = ncl * CLSIZE;
438792Sroot 	mbx = rmalloc(mbmap, (long)npg);
44*21107Skarels 	if (mbx == 0) {
45*21107Skarels 		if (canwait == M_WAIT)
46*21107Skarels 			panic("out of mbuf map");
475228Swnj 		return (0);
48*21107Skarels 	}
495228Swnj 	m = cltom(mbx / CLSIZE);
509765Ssam 	if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
519765Ssam 		rmfree(mbmap, (long)npg, (long)mbx);
525228Swnj 		return (0);
539765Ssam 	}
545228Swnj 	vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
555228Swnj 	switch (how) {
565228Swnj 
575228Swnj 	case MPG_CLUSTERS:
585228Swnj 		for (i = 0; i < ncl; i++) {
595228Swnj 			m->m_off = 0;
605228Swnj 			m->m_next = mclfree;
615228Swnj 			mclfree = m;
625228Swnj 			m += CLBYTES / sizeof (*m);
636839Ssam 			mbstat.m_clfree++;
645228Swnj 		}
655228Swnj 		mbstat.m_clusters += ncl;
665228Swnj 		break;
675228Swnj 
685228Swnj 	case MPG_MBUFS:
695228Swnj 		for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
705228Swnj 			m->m_off = 0;
719634Ssam 			m->m_type = MT_DATA;
729634Ssam 			mbstat.m_mtypes[MT_DATA]++;
736839Ssam 			mbstat.m_mbufs++;
745228Swnj 			(void) m_free(m);
755228Swnj 			m++;
765228Swnj 		}
775232Swnj 		break;
785228Swnj 	}
795228Swnj 	return ((caddr_t)m);
805228Swnj }
815228Swnj 
825228Swnj m_pgfree(addr, n)
835228Swnj 	caddr_t addr;
845228Swnj 	int n;
855228Swnj {
865228Swnj 
876141Ssam #ifdef lint
886141Ssam 	addr = addr; n = n;
896141Ssam #endif
905228Swnj }
915228Swnj 
92*21107Skarels /*
93*21107Skarels  * Must be called at splimp.
94*21107Skarels  */
95*21107Skarels m_expand(canwait)
96*21107Skarels 	int canwait;
975228Swnj {
985228Swnj 
99*21107Skarels 	if (m_clalloc(1, MPG_MBUFS, canwait) == 0)
1005228Swnj 		goto steal;
1015228Swnj 	return (1);
1025228Swnj steal:
1035228Swnj 	/* should ask protocols to free code */
1045228Swnj 	return (0);
1055228Swnj }
1065228Swnj 
1075228Swnj /* NEED SOME WAY TO RELEASE SPACE */
1085228Swnj 
1095228Swnj /*
1105228Swnj  * Space allocation routines.
1115228Swnj  * These are also available as macros
1125228Swnj  * for critical paths.
1135228Swnj  */
1144585Swnj struct mbuf *
1159634Ssam m_get(canwait, type)
1169634Ssam 	int canwait, type;
1174585Swnj {
1184585Swnj 	register struct mbuf *m;
1194585Swnj 
1209634Ssam 	MGET(m, canwait, type);
1214585Swnj 	return (m);
1224585Swnj }
1234585Swnj 
1244585Swnj struct mbuf *
1259634Ssam m_getclr(canwait, type)
1269634Ssam 	int canwait, type;
1274890Swnj {
1284890Swnj 	register struct mbuf *m;
1294890Swnj 
130*21107Skarels 	MGET(m, canwait, type);
1314890Swnj 	if (m == 0)
1324890Swnj 		return (0);
1334890Swnj 	bzero(mtod(m, caddr_t), MLEN);
1344890Swnj 	return (m);
1354890Swnj }
1364890Swnj 
1374890Swnj struct mbuf *
1384585Swnj m_free(m)
1394585Swnj 	struct mbuf *m;
1404585Swnj {
1414585Swnj 	register struct mbuf *n;
1424585Swnj 
1434585Swnj 	MFREE(m, n);
1444585Swnj 	return (n);
1454585Swnj }
1464585Swnj 
147*21107Skarels /*
148*21107Skarels  * Get more mbufs; called from MGET macro if mfree list is empty.
149*21107Skarels  * Must be called at splimp.
150*21107Skarels  */
1514916Swnj /*ARGSUSED*/
1524585Swnj struct mbuf *
1539634Ssam m_more(canwait, type)
1549634Ssam 	int canwait, type;
1554585Swnj {
1564585Swnj 	register struct mbuf *m;
1574585Swnj 
158*21107Skarels 	while (m_expand(canwait) == 0) {
159*21107Skarels 		if (canwait == M_WAIT) {
160*21107Skarels 			m_want++;
161*21107Skarels 			sleep((caddr_t)mfree, PZERO - 1);
162*21107Skarels 		} else {
163*21107Skarels 			mbstat.m_drops++;
164*21107Skarels 			return (NULL);
165*21107Skarels 		}
1664585Swnj 	}
1679634Ssam #define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
1689634Ssam 	MGET(m, canwait, type);
1695282Sroot #undef m_more
1704585Swnj 	return (m);
1714585Swnj }
1724585Swnj 
1734669Swnj m_freem(m)
1744585Swnj 	register struct mbuf *m;
1754585Swnj {
1764585Swnj 	register struct mbuf *n;
1774927Swnj 	register int s;
1784585Swnj 
1794585Swnj 	if (m == NULL)
1804916Swnj 		return;
1814662Swnj 	s = splimp();
1824585Swnj 	do {
1834585Swnj 		MFREE(m, n);
1844585Swnj 	} while (m = n);
1854585Swnj 	splx(s);
1864585Swnj }
1874585Swnj 
1885228Swnj /*
1895228Swnj  * Mbuffer utility routines.
1905228Swnj  */
191*21107Skarels 
192*21107Skarels /*
193*21107Skarels  * Make a copy of an mbuf chain starting "off" bytes from the beginning,
194*21107Skarels  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
195*21107Skarels  * Should get M_WAIT/M_DONTWAIT from caller.
196*21107Skarels  */
1974927Swnj struct mbuf *
1984927Swnj m_copy(m, off, len)
1994927Swnj 	register struct mbuf *m;
2004927Swnj 	int off;
2014927Swnj 	register int len;
2024927Swnj {
2034927Swnj 	register struct mbuf *n, **np;
2044927Swnj 	struct mbuf *top, *p;
2054927Swnj 
2064927Swnj 	if (len == 0)
2074927Swnj 		return (0);
2084927Swnj 	if (off < 0 || len < 0)
2094927Swnj 		panic("m_copy");
2104927Swnj 	while (off > 0) {
2114927Swnj 		if (m == 0)
2124927Swnj 			panic("m_copy");
2134927Swnj 		if (off < m->m_len)
2144927Swnj 			break;
2154927Swnj 		off -= m->m_len;
2164927Swnj 		m = m->m_next;
2174927Swnj 	}
2184927Swnj 	np = &top;
2194927Swnj 	top = 0;
2204927Swnj 	while (len > 0) {
2215609Swnj 		if (m == 0) {
2225609Swnj 			if (len != M_COPYALL)
2235609Swnj 				panic("m_copy");
2245609Swnj 			break;
2255609Swnj 		}
226*21107Skarels 		MGET(n, M_DONTWAIT, m->m_type);
2274927Swnj 		*np = n;
2284927Swnj 		if (n == 0)
2294927Swnj 			goto nospace;
2304927Swnj 		n->m_len = MIN(len, m->m_len - off);
2314927Swnj 		if (m->m_off > MMAXOFF) {
2324927Swnj 			p = mtod(m, struct mbuf *);
2334927Swnj 			n->m_off = ((int)p - (int)n) + off;
2345090Swnj 			mclrefcnt[mtocl(p)]++;
2358318Sroot 		} else
2364927Swnj 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
2374927Swnj 			    (unsigned)n->m_len);
2385609Swnj 		if (len != M_COPYALL)
2395609Swnj 			len -= n->m_len;
2404927Swnj 		off = 0;
2414927Swnj 		m = m->m_next;
2424927Swnj 		np = &n->m_next;
2434927Swnj 	}
2444927Swnj 	return (top);
2454927Swnj nospace:
2464927Swnj 	m_freem(top);
2474927Swnj 	return (0);
2484927Swnj }
2494927Swnj 
2504669Swnj m_cat(m, n)
2514669Swnj 	register struct mbuf *m, *n;
2524669Swnj {
2534669Swnj 	while (m->m_next)
2544669Swnj 		m = m->m_next;
2556091Sroot 	while (n) {
2566091Sroot 		if (m->m_off >= MMAXOFF ||
2576091Sroot 		    m->m_off + m->m_len + n->m_len > MMAXOFF) {
2586091Sroot 			/* just join the two chains */
2594669Swnj 			m->m_next = n;
2606091Sroot 			return;
2614669Swnj 		}
2626091Sroot 		/* splat the data from one into the other */
2636091Sroot 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
2646091Sroot 		    (u_int)n->m_len);
2656091Sroot 		m->m_len += n->m_len;
2666091Sroot 		n = m_free(n);
2676091Sroot 	}
2684669Swnj }
2694669Swnj 
2704585Swnj m_adj(mp, len)
2714585Swnj 	struct mbuf *mp;
2724916Swnj 	register int len;
2734585Swnj {
2744585Swnj 	register struct mbuf *m, *n;
2754585Swnj 
2764585Swnj 	if ((m = mp) == NULL)
2774585Swnj 		return;
2784822Swnj 	if (len >= 0) {
2794585Swnj 		while (m != NULL && len > 0) {
2804822Swnj 			if (m->m_len <= len) {
2814585Swnj 				len -= m->m_len;
2824585Swnj 				m->m_len = 0;
2834585Swnj 				m = m->m_next;
2844822Swnj 			} else {
2854585Swnj 				m->m_len -= len;
2864585Swnj 				m->m_off += len;
2874585Swnj 				break;
2884585Swnj 			}
2894585Swnj 		}
2904822Swnj 	} else {
2914822Swnj 		/* a 2 pass algorithm might be better */
2924585Swnj 		len = -len;
2934585Swnj 		while (len > 0 && m->m_len != 0) {
2944585Swnj 			while (m != NULL && m->m_len != 0) {
2954585Swnj 				n = m;
2964585Swnj 				m = m->m_next;
2974585Swnj 			}
2984822Swnj 			if (n->m_len <= len) {
2994585Swnj 				len -= n->m_len;
3004585Swnj 				n->m_len = 0;
3014585Swnj 				m = mp;
3024822Swnj 			} else {
3034585Swnj 				n->m_len -= len;
3044585Swnj 				break;
3054585Swnj 			}
3064585Swnj 		}
3074585Swnj 	}
3084585Swnj }
3095228Swnj 
3105310Sroot struct mbuf *
3115310Sroot m_pullup(m0, len)
3125310Sroot 	struct mbuf *m0;
3135228Swnj 	int len;
3145228Swnj {
3155310Sroot 	register struct mbuf *m, *n;
3166164Ssam 	int count;
3175228Swnj 
3185732Sroot 	n = m0;
3195310Sroot 	if (len > MLEN)
3205310Sroot 		goto bad;
3219634Ssam 	MGET(m, M_DONTWAIT, n->m_type);
3225310Sroot 	if (m == 0)
3235310Sroot 		goto bad;
3245310Sroot 	m->m_len = 0;
3255310Sroot 	do {
3266164Ssam 		count = MIN(MLEN - m->m_len, len);
3276164Ssam 		if (count > n->m_len)
3286164Ssam 			count = n->m_len;
3296164Ssam 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
3306164Ssam 		  (unsigned)count);
3316164Ssam 		len -= count;
3326164Ssam 		m->m_len += count;
3336164Ssam 		n->m_off += count;
3346164Ssam 		n->m_len -= count;
3355310Sroot 		if (n->m_len)
3365310Sroot 			break;
3375310Sroot 		n = m_free(n);
3385310Sroot 	} while (n);
3395310Sroot 	if (len) {
3405310Sroot 		(void) m_free(m);
3415310Sroot 		goto bad;
3425310Sroot 	}
3435310Sroot 	m->m_next = n;
3445310Sroot 	return (m);
3455310Sroot bad:
3465732Sroot 	m_freem(n);
3475228Swnj 	return (0);
3485228Swnj }
349