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