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