Removed all patch kit headers, sccsid and rcsid strings, put $Id$ in, some
[unix-history] / sys / kern / uipc_mbuf.c
CommitLineData
15637ed4
RG
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 *
600f7f07
RG
33 * from: @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91
34 * $Id$
15637ed4
RG
35 */
36
37#include "param.h"
dd18dc33 38#include "systm.h"
15637ed4
RG
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
49extern vm_map_t mb_map;
50struct mbuf *mbutl;
51char *mclrefcnt;
52
53mbinit()
54{
55 int s;
56
57#if CLBYTES < 4096
58#define NCL_INIT (4096/CLBYTES)
59#else
60#define NCL_INIT 1
61#endif
62 s = splimp();
63 if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
64 goto bad;
65 splx(s);
66 return;
67bad:
68 panic("mbinit");
69}
70
71/*
72 * Allocate some number of mbuf clusters
73 * and place on cluster free list.
74 * Must be called at splimp.
75 */
76/* ARGSUSED */
77m_clalloc(ncl, how) /* 31 Aug 92*/
78 register int ncl;
79{
80 int npg, mbx;
81 register caddr_t p;
82 register int i;
83 static int logged;
84
85 npg = ncl * CLSIZE;
86 /* 31 Aug 92*/
87 p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !(how&M_DONTWAIT));
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 */
110struct mbuf *
111m_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 */
126struct mbuf *
127m_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
139m_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 */
158struct mbuf *
159m_get(how, type) /* 31 Aug 92*/
160 int how, type;
161{
162 register struct mbuf *m;
163
164 MGET(m, how, type);
165 return (m);
166}
167
168struct mbuf *
169m_gethdr(how, type) /* 31 Aug 92*/
170 int how, type;
171{
172 register struct mbuf *m;
173
174 MGETHDR(m, how, type);
175 return (m);
176}
177
178struct mbuf *
179m_getclr(how, type) /* 31 Aug 92*/
180 int how, type;
181{
182 register struct mbuf *m;
183
184 MGET(m, how, type);
185 if (m == 0)
186 return (0);
187 bzero(mtod(m, caddr_t), MLEN);
188 return (m);
189}
190
191struct mbuf *
192m_free(m)
193 struct mbuf *m;
194{
195 register struct mbuf *n;
196
197 MFREE(m, n);
198 return (n);
199}
200
201m_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 */
222struct mbuf *
223m_prepend(m, len, how)
224 register struct mbuf *m;
225 int len, how;
226{
227 struct mbuf *mn;
228
229 MGET(mn, how, 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 */
251int MCFail;
252
253struct mbuf *
254m_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);
314nospace:
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 */
324m_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 */
359m_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
379m_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 */
459int MPFail;
460
461struct mbuf *
462m_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);
514bad:
515 m_freem(n);
516 MPFail++;
517 return (0);
518}