|
|
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: #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 = ⊤
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.