Home | History | Annotate | Line # | Download | only in kern
uipc_mbuf.c revision 1.2
      1 /*
      2  * Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  *	@(#)uipc_mbuf.c	7.19 (Berkeley) 4/20/91
     34  *
     35  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
     36  * --------------------         -----   ----------------------
     37  * CURRENT PATCH LEVEL:         1       00009
     38  * --------------------         -----   ----------------------
     39  *
     40  * 31 Aug 92	Wolfgang Solfrank	Fixed mbuf allocation code
     41  */
     42 
     43 #include "param.h"
     44 #include "proc.h"
     45 #include "malloc.h"
     46 #define MBTYPES
     47 #include "mbuf.h"
     48 #include "kernel.h"
     49 #include "syslog.h"
     50 #include "domain.h"
     51 #include "protosw.h"
     52 #include "vm/vm.h"
     53 
     54 extern	vm_map_t mb_map;
     55 struct	mbuf *mbutl;
     56 char	*mclrefcnt;
     57 
     58 mbinit()
     59 {
     60 	int s;
     61 
     62 #if CLBYTES < 4096
     63 #define NCL_INIT	(4096/CLBYTES)
     64 #else
     65 #define NCL_INIT	1
     66 #endif
     67 	s = splimp();
     68 	if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
     69 		goto bad;
     70 	splx(s);
     71 	return;
     72 bad:
     73 	panic("mbinit");
     74 }
     75 
     76 /*
     77  * Allocate some number of mbuf clusters
     78  * and place on cluster free list.
     79  * Must be called at splimp.
     80  */
     81 /* ARGSUSED */
     82 m_clalloc(ncl, how)				/* 31 Aug 92*/
     83 	register int ncl;
     84 {
     85 	int npg, mbx;
     86 	register caddr_t p;
     87 	register int i;
     88 	static int logged;
     89 
     90 	npg = ncl * CLSIZE;
     91 	/* 31 Aug 92*/
     92 	p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !(how&M_DONTWAIT));
     93 	if (p == NULL) {
     94 		if (logged == 0) {
     95 			logged++;
     96 			log(LOG_ERR, "mb_map full\n");
     97 		}
     98 		return (0);
     99 	}
    100 	ncl = ncl * CLBYTES / MCLBYTES;
    101 	for (i = 0; i < ncl; i++) {
    102 		((union mcluster *)p)->mcl_next = mclfree;
    103 		mclfree = (union mcluster *)p;
    104 		p += MCLBYTES;
    105 		mbstat.m_clfree++;
    106 	}
    107 	mbstat.m_clusters += ncl;
    108 	return (1);
    109 }
    110 
    111 /*
    112  * When MGET failes, ask protocols to free space when short of memory,
    113  * then re-attempt to allocate an mbuf.
    114  */
    115 struct mbuf *
    116 m_retry(i, t)
    117 	int i, t;
    118 {
    119 	register struct mbuf *m;
    120 
    121 	m_reclaim();
    122 #define m_retry(i, t)	(struct mbuf *)0
    123 	MGET(m, i, t);
    124 #undef m_retry
    125 	return (m);
    126 }
    127 
    128 /*
    129  * As above; retry an MGETHDR.
    130  */
    131 struct mbuf *
    132 m_retryhdr(i, t)
    133 	int i, t;
    134 {
    135 	register struct mbuf *m;
    136 
    137 	m_reclaim();
    138 #define m_retryhdr(i, t) (struct mbuf *)0
    139 	MGETHDR(m, i, t);
    140 #undef m_retryhdr
    141 	return (m);
    142 }
    143 
    144 m_reclaim()
    145 {
    146 	register struct domain *dp;
    147 	register struct protosw *pr;
    148 	int s = splimp();
    149 
    150 	for (dp = domains; dp; dp = dp->dom_next)
    151 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
    152 			if (pr->pr_drain)
    153 				(*pr->pr_drain)();
    154 	splx(s);
    155 	mbstat.m_drain++;
    156 }
    157 
    158 /*
    159  * Space allocation routines.
    160  * These are also available as macros
    161  * for critical paths.
    162  */
    163 struct mbuf *
    164 m_get(how, type)				/* 31 Aug 92*/
    165 	int how, type;
    166 {
    167 	register struct mbuf *m;
    168 
    169 	MGET(m, how, type);
    170 	return (m);
    171 }
    172 
    173 struct mbuf *
    174 m_gethdr(how, type)				/* 31 Aug 92*/
    175 	int how, type;
    176 {
    177 	register struct mbuf *m;
    178 
    179 	MGETHDR(m, how, type);
    180 	return (m);
    181 }
    182 
    183 struct mbuf *
    184 m_getclr(how, type)				/* 31 Aug 92*/
    185 	int how, type;
    186 {
    187 	register struct mbuf *m;
    188 
    189 	MGET(m, how, type);
    190 	if (m == 0)
    191 		return (0);
    192 	bzero(mtod(m, caddr_t), MLEN);
    193 	return (m);
    194 }
    195 
    196 struct mbuf *
    197 m_free(m)
    198 	struct mbuf *m;
    199 {
    200 	register struct mbuf *n;
    201 
    202 	MFREE(m, n);
    203 	return (n);
    204 }
    205 
    206 m_freem(m)
    207 	register struct mbuf *m;
    208 {
    209 	register struct mbuf *n;
    210 
    211 	if (m == NULL)
    212 		return;
    213 	do {
    214 		MFREE(m, n);
    215 	} while (m = n);
    216 }
    217 
    218 /*
    219  * Mbuffer utility routines.
    220  */
    221 
    222 /*
    223  * Lesser-used path for M_PREPEND:
    224  * allocate new mbuf to prepend to chain,
    225  * copy junk along.
    226  */
    227 struct mbuf *
    228 m_prepend(m, len, how)
    229 	register struct mbuf *m;
    230 	int len, how;
    231 {
    232 	struct mbuf *mn;
    233 
    234 	MGET(mn, how, m->m_type);
    235 	if (mn == (struct mbuf *)NULL) {
    236 		m_freem(m);
    237 		return ((struct mbuf *)NULL);
    238 	}
    239 	if (m->m_flags & M_PKTHDR) {
    240 		M_COPY_PKTHDR(mn, m);
    241 		m->m_flags &= ~M_PKTHDR;
    242 	}
    243 	mn->m_next = m;
    244 	m = mn;
    245 	if (len < MHLEN)
    246 		MH_ALIGN(m, len);
    247 	m->m_len = len;
    248 	return (m);
    249 }
    250 
    251 /*
    252  * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
    253  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
    254  * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
    255  */
    256 int MCFail;
    257 
    258 struct mbuf *
    259 m_copym(m, off0, len, wait)
    260 	register struct mbuf *m;
    261 	int off0, wait;
    262 	register int len;
    263 {
    264 	register struct mbuf *n, **np;
    265 	register int off = off0;
    266 	struct mbuf *top;
    267 	int copyhdr = 0;
    268 
    269 	if (off < 0 || len < 0)
    270 		panic("m_copym");
    271 	if (off == 0 && m->m_flags & M_PKTHDR)
    272 		copyhdr = 1;
    273 	while (off > 0) {
    274 		if (m == 0)
    275 			panic("m_copym");
    276 		if (off < m->m_len)
    277 			break;
    278 		off -= m->m_len;
    279 		m = m->m_next;
    280 	}
    281 	np = &top;
    282 	top = 0;
    283 	while (len > 0) {
    284 		if (m == 0) {
    285 			if (len != M_COPYALL)
    286 				panic("m_copym");
    287 			break;
    288 		}
    289 		MGET(n, wait, m->m_type);
    290 		*np = n;
    291 		if (n == 0)
    292 			goto nospace;
    293 		if (copyhdr) {
    294 			M_COPY_PKTHDR(n, m);
    295 			if (len == M_COPYALL)
    296 				n->m_pkthdr.len -= off0;
    297 			else
    298 				n->m_pkthdr.len = len;
    299 			copyhdr = 0;
    300 		}
    301 		n->m_len = MIN(len, m->m_len - off);
    302 		if (m->m_flags & M_EXT) {
    303 			n->m_data = m->m_data + off;
    304 			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
    305 			n->m_ext = m->m_ext;
    306 			n->m_flags |= M_EXT;
    307 		} else
    308 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
    309 			    (unsigned)n->m_len);
    310 		if (len != M_COPYALL)
    311 			len -= n->m_len;
    312 		off = 0;
    313 		m = m->m_next;
    314 		np = &n->m_next;
    315 	}
    316 	if (top == 0)
    317 		MCFail++;
    318 	return (top);
    319 nospace:
    320 	m_freem(top);
    321 	MCFail++;
    322 	return (0);
    323 }
    324 
    325 /*
    326  * Copy data from an mbuf chain starting "off" bytes from the beginning,
    327  * continuing for "len" bytes, into the indicated buffer.
    328  */
    329 m_copydata(m, off, len, cp)
    330 	register struct mbuf *m;
    331 	register int off;
    332 	register int len;
    333 	caddr_t cp;
    334 {
    335 	register unsigned count;
    336 
    337 	if (off < 0 || len < 0)
    338 		panic("m_copydata");
    339 	while (off > 0) {
    340 		if (m == 0)
    341 			panic("m_copydata");
    342 		if (off < m->m_len)
    343 			break;
    344 		off -= m->m_len;
    345 		m = m->m_next;
    346 	}
    347 	while (len > 0) {
    348 		if (m == 0)
    349 			panic("m_copydata");
    350 		count = MIN(m->m_len - off, len);
    351 		bcopy(mtod(m, caddr_t) + off, cp, count);
    352 		len -= count;
    353 		cp += count;
    354 		off = 0;
    355 		m = m->m_next;
    356 	}
    357 }
    358 
    359 /*
    360  * Concatenate mbuf chain n to m.
    361  * Both chains must be of the same type (e.g. MT_DATA).
    362  * Any m_pkthdr is not updated.
    363  */
    364 m_cat(m, n)
    365 	register struct mbuf *m, *n;
    366 {
    367 	while (m->m_next)
    368 		m = m->m_next;
    369 	while (n) {
    370 		if (m->m_flags & M_EXT ||
    371 		    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
    372 			/* just join the two chains */
    373 			m->m_next = n;
    374 			return;
    375 		}
    376 		/* splat the data from one into the other */
    377 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
    378 		    (u_int)n->m_len);
    379 		m->m_len += n->m_len;
    380 		n = m_free(n);
    381 	}
    382 }
    383 
    384 m_adj(mp, req_len)
    385 	struct mbuf *mp;
    386 {
    387 	register int len = req_len;
    388 	register struct mbuf *m;
    389 	register count;
    390 
    391 	if ((m = mp) == NULL)
    392 		return;
    393 	if (len >= 0) {
    394 		/*
    395 		 * Trim from head.
    396 		 */
    397 		while (m != NULL && len > 0) {
    398 			if (m->m_len <= len) {
    399 				len -= m->m_len;
    400 				m->m_len = 0;
    401 				m = m->m_next;
    402 			} else {
    403 				m->m_len -= len;
    404 				m->m_data += len;
    405 				len = 0;
    406 			}
    407 		}
    408 		m = mp;
    409 		if (mp->m_flags & M_PKTHDR)
    410 			m->m_pkthdr.len -= (req_len - len);
    411 	} else {
    412 		/*
    413 		 * Trim from tail.  Scan the mbuf chain,
    414 		 * calculating its length and finding the last mbuf.
    415 		 * If the adjustment only affects this mbuf, then just
    416 		 * adjust and return.  Otherwise, rescan and truncate
    417 		 * after the remaining size.
    418 		 */
    419 		len = -len;
    420 		count = 0;
    421 		for (;;) {
    422 			count += m->m_len;
    423 			if (m->m_next == (struct mbuf *)0)
    424 				break;
    425 			m = m->m_next;
    426 		}
    427 		if (m->m_len >= len) {
    428 			m->m_len -= len;
    429 			if ((mp = m)->m_flags & M_PKTHDR)
    430 				m->m_pkthdr.len -= len;
    431 			return;
    432 		}
    433 		count -= len;
    434 		if (count < 0)
    435 			count = 0;
    436 		/*
    437 		 * Correct length for chain is "count".
    438 		 * Find the mbuf with last data, adjust its length,
    439 		 * and toss data from remaining mbufs on chain.
    440 		 */
    441 		m = mp;
    442 		if (m->m_flags & M_PKTHDR)
    443 			m->m_pkthdr.len = count;
    444 		for (; m; m = m->m_next) {
    445 			if (m->m_len >= count) {
    446 				m->m_len = count;
    447 				break;
    448 			}
    449 			count -= m->m_len;
    450 		}
    451 		while (m = m->m_next)
    452 			m->m_len = 0;
    453 	}
    454 }
    455 
    456 /*
    457  * Rearange an mbuf chain so that len bytes are contiguous
    458  * and in the data area of an mbuf (so that mtod and dtom
    459  * will work for a structure of size len).  Returns the resulting
    460  * mbuf chain on success, frees it and returns null on failure.
    461  * If there is room, it will add up to max_protohdr-len extra bytes to the
    462  * contiguous region in an attempt to avoid being called next time.
    463  */
    464 int MPFail;
    465 
    466 struct mbuf *
    467 m_pullup(n, len)
    468 	register struct mbuf *n;
    469 	int len;
    470 {
    471 	register struct mbuf *m;
    472 	register int count;
    473 	int space;
    474 
    475 	/*
    476 	 * If first mbuf has no cluster, and has room for len bytes
    477 	 * without shifting current data, pullup into it,
    478 	 * otherwise allocate a new mbuf to prepend to the chain.
    479 	 */
    480 	if ((n->m_flags & M_EXT) == 0 &&
    481 	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
    482 		if (n->m_len >= len)
    483 			return (n);
    484 		m = n;
    485 		n = n->m_next;
    486 		len -= m->m_len;
    487 	} else {
    488 		if (len > MHLEN)
    489 			goto bad;
    490 		MGET(m, M_DONTWAIT, n->m_type);
    491 		if (m == 0)
    492 			goto bad;
    493 		m->m_len = 0;
    494 		if (n->m_flags & M_PKTHDR) {
    495 			M_COPY_PKTHDR(m, n);
    496 			n->m_flags &= ~M_PKTHDR;
    497 		}
    498 	}
    499 	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
    500 	do {
    501 		count = min(min(max(len, max_protohdr), space), n->m_len);
    502 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
    503 		  (unsigned)count);
    504 		len -= count;
    505 		m->m_len += count;
    506 		n->m_len -= count;
    507 		space -= count;
    508 		if (n->m_len)
    509 			n->m_data += count;
    510 		else
    511 			n = m_free(n);
    512 	} while (len > 0 && n);
    513 	if (len > 0) {
    514 		(void) m_free(m);
    515 		goto bad;
    516 	}
    517 	m->m_next = n;
    518 	return (m);
    519 bad:
    520 	m_freem(n);
    521 	MPFail++;
    522 	return (0);
    523 }
    524