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