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